Search-based refactoring initialization
Introduction
This module implements finding refactoring candidates for the search-based algorithms
Initialization: The abstract class and common utility functions. RandomInitialization: For initialling random candidates.
Changelog
Version 0.4.0
- Enhances module's design.
Version 0.3.2
Initialization
The superclass of initialization contains init_refactoring methods
Source code in codart\sbse\initialize.py
class Initialization(object):
"""
The superclass of initialization contains init_refactoring methods
"""
def __init__(self, udb_path, population_size=50, lower_band=10, upper_band=50):
"""
Args:
udb_path (str): Path for understand database file.
population_size (int): The length of population for GA.
lower_band (int): The minimum length of individual for GA.
upper_band (int): The maximum length of individual for GA.
Returns:
None
"""
random.seed(None)
self.udb_path = udb_path
self.population_size = population_size
self.lower_band = lower_band
self.upper_band = upper_band
self.population = []
self.initializers = (
self.init_make_field_non_static, # 0
self.init_make_field_static, # 1
self.init_make_method_static, # 2
self.init_make_method_non_static, # 3
self.init_pullup_field, # 4
self.init_move_field, # 5
self.init_move_method, # 6
# self.init_move_method, # 6.2
self.init_move_class, # 7
# self.init_move_class, # 7.2
self.init_push_down_field, # 8
self.init_extract_class, # 9
# self.init_extract_class, # 9.2
self.init_pullup_method, # 10
self.init_push_down_method, # 11
self.init_pullup_constructor, # 12
self.init_decrease_field_visibility, # 13
self.init_increase_field_visibility, # 14
self.init_decrease_method_visibility, # 15
self.init_increase_method_visibility, # 16
self.init_extract_interface, # 17
# self.init_extract_interface, # 17.2
# self.init_extract_method, # 18
)
self._variables = self.get_all_variables()
self._static_variables = self.get_all_variables(static=True)
self._methods = self.get_all_methods()
self._static_methods = self.get_all_methods(static=True)
self._pullup_field_candidates = self.find_pullup_field_candidates()
self._push_down_field_candidates = self.find_push_down_field_candidates()
self._pullup_method_candidates = self.find_pullup_method_candidates()
self._pullup_constructor_candidates = self.find_pullup_constructor_candidates()
self._push_down_method_candidates = self.find_push_down_method_candidates()
self._extract_interface_candidates = self.find_extract_interface_candidate()
def __del__(self):
# logger.info("Understand database closed after initialization.")
# self._und.close()
pass
def get_all_methods(self, static=False):
_db = und.open(self.udb_path)
candidates = []
if static:
query = _db.ents("Static Method")
blacklist = ('abstract', 'unknown', 'constructor',)
else:
query = _db.ents("Method")
blacklist = ('constructor', 'static', 'abstract', 'unknown',)
for ent in query:
kind_name = ent.kindname().lower()
if any(word in kind_name for word in blacklist):
continue
parent = ent.parent()
if parent is None:
continue
if not parent.kind().check("class") or parent.kind().check("anonymous"):
continue
long_name = parent.longname().split('.')
method_name = ent.simplename()
if len(long_name) == 1:
source_class = long_name[-1]
source_package = None
elif len(long_name) > 1:
source_class = long_name[-1]
source_package = ".".join(long_name[:-1])
else:
continue
is_public = ent.kind().check('public')
is_private = ent.kind().check('private')
external_references = 0
for ref in ent.refs('Callby, Overrideby'):
if '.'.join(long_name[:-1]) not in ref.ent().longname():
external_references += 1
candidates.append(
{
'source_package': source_package, 'source_class': source_class, 'method_name': method_name,
'is_public': is_public, 'is_private': is_private, 'external_references': external_references
}
)
_db.close()
return candidates
def get_all_variables(self, static=False):
_db = und.open(self.udb_path)
candidates = []
if static:
query = _db.ents("Static Variable")
blacklist = ()
else:
query = _db.ents("Variable")
blacklist = ('static',)
for ent in query:
kind_name = ent.kindname().lower()
if any(word in kind_name for word in blacklist):
continue
parent = ent.parent()
if parent is None:
continue
if not parent.kind().check("class") or parent.kind().check("anonymous"):
continue
source_package = None
long_name = ent.longname().split(".")
if len(long_name) >= 3:
source_package = '.'.join(long_name[:-2])
source_class, field_name = long_name[-2:]
elif len(long_name) == 2:
source_class, field_name = long_name
else:
continue
is_public = ent.kind().check('public')
is_private = ent.kind().check('private')
external_references = 0
for ref in ent.refs('Setby, Useby'):
if '.'.join(long_name[:-1]) not in ref.ent().longname():
external_references += 1
candidates.append(
{
'source_package': source_package, 'source_class': source_class, 'field_name': field_name,
'is_public': is_public, 'is_private': is_private, 'external_references': external_references
}
)
_db.close()
return candidates
# def get_all_class_entities(self, filter_="class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static"):
# query = self._und.ents(filter_)
# class_entities = []
# for ent in query:
# class_entities.append(ent)
# return class_entities
# return query
def find_pullup_field_candidates(self):
_db = und.open(self.udb_path)
candidates = []
class_entities = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
for ent in class_entities:
for ref in ent.refs("Define", "Variable"):
candidate = {
"package_name": get_package_from_class(ent.longname()),
"children_class": ent.simplename(),
"field_name": ref.ent().simplename()
}
candidates.append(candidate)
_db.close()
return candidates
def find_push_down_field_candidates(self):
_db = und.open(self.udb_path)
candidates = []
class_entities = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
for ent in class_entities:
params = {
"source_class": "",
"source_package": "",
"field_name": "",
"target_classes": []
}
field_names = []
for ref in ent.refs("ExtendBy ~Implicit"):
params["source_class"] = ent.simplename()
params["source_package"] = get_package_from_class(ent.longname())
if len(params["target_classes"]) >= 1:
rnd = random.randint(0, 1)
if rnd == 0:
params["target_classes"].append(ref.ent().simplename())
else:
params["target_classes"].append(ref.ent().simplename())
for ref in ent.refs("define", "variable"):
field_names.append(ref.ent().simplename())
if field_names:
params["field_name"] = random.choice(field_names)
else:
continue
if params["source_class"] != "":
candidates.append(params)
_db.close()
return candidates
def find_pullup_method_candidates(self):
_db = und.open(self.udb_path)
candidates = []
class_entities = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
common_methods = []
for ent in class_entities:
children = []
class_method_dict = {}
father_methods = []
for met_ref in ent.refs("Define", "Method ~Override"):
method = met_ref.ent()
father_methods.append(method.simplename())
for ref in ent.refs("Extendby"):
child = ref.ent()
if not child.kind().check("public class"):
continue
child_name = child.simplename()
children.append(child_name)
if child_name not in class_method_dict:
class_method_dict[child_name] = []
for met_ref in child.refs("Define", "Method"):
method = met_ref.ent()
method_name = method.simplename()
if method.ents("Override"):
continue
if method_name not in father_methods:
common_methods.append(method_name)
class_method_dict[child_name].append(method_name)
counts = Counter(common_methods)
common_methods = [value for value, count in counts.items() if count > 1]
if len(common_methods) > 0:
random_method = random.choice(common_methods)
children = [k for k, v in class_method_dict.items() if random_method in v]
if len(children) > 1:
candidates.append({
"method_name": random.choice(common_methods),
"children_classes": children
})
_db.close()
return candidates
def find_pullup_constructor_candidates(self):
_db = und.open(self.udb_path)
candidates = []
class_entities = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
for ent in class_entities:
children = []
params = {}
for ref in ent.refs("Extendby"):
child = ref.ent()
if not child.kind().check("public class"):
continue
child_name = child.simplename()
children.append(child_name)
ln = ent.longname().split(".")
params["source_package"] = ".".join(ln[:-1]) if len(ln) > 1 else ""
params["target_class"] = ent.simplename()
if len(children) >= 2:
params["class_names"] = random.sample(children, random.randint(2, len(children)))
candidates.append(params)
_db.close()
return candidates
def find_push_down_method_candidates(self):
_db = und.open(self.udb_path)
candidates = []
class_entities = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
for ent in class_entities:
params = {
"source_class": "",
"source_package": "",
"method_name": "",
"target_classes": []
}
method_names = []
for ref in ent.refs("Extendby ~Implicit", "Public Class"):
params["source_class"] = ent.simplename()
ln = ent.longname().split(".")
params["source_package"] = ln[0] if len(ln) > 1 else ""
params["target_classes"].append(ref.ent().simplename())
for ref in ent.refs("Define", "Method"):
method_names.append(ref.ent().simplename())
if method_names:
params["method_name"] = random.choice(method_names)
else:
continue
if params["target_classes"]:
params["target_classes"] = [random.choice(params["target_classes"])]
else:
continue
if params["source_class"] != "":
candidates.append(params)
_db.close()
return candidates
def find_extract_interface_candidate(self):
_db = und.open(config.UDB_PATH)
extract_interface_refactoring_candidates = []
classes = _db.ents("Type Class Public ~Generic ~Interface ~Enum ~Unknown ~Anonymous ~TypeVariable")
for class_entity in classes:
class_path = class_entity.parent().longname()
if os.path.exists(class_path):
filter_inherited_attrs = 'Java Extend Couple ~Implicit, Java Implement Couple ~Implicit'
filter_inherited_attrs = 'Java Implement Couple ~Implicit'
inherited_entities = class_entity.ents(filter_inherited_attrs)
if len(inherited_entities) == 0:
public_methods = len(class_entity.ents("Define", "Java Method Member ~Private ~Static"))
if public_methods > 0:
extract_interface_refactoring_candidates.append(class_path)
_db.close()
return extract_interface_refactoring_candidates
def init_make_field_non_static(self):
pass
def init_make_field_static(self):
pass
def init_make_method_static(self):
pass
def init_make_method_non_static(self):
pass
def init_pullup_field(self):
pass
def init_push_down_field(self):
pass
def init_pullup_method(self):
pass
def init_pullup_constructor(self):
pass
def init_push_down_method(self):
pass
def init_move_field(self):
pass
def init_move_method(self):
pass
def init_move_class(self):
pass
def init_extract_class(self):
pass
def init_extract_method(self):
pass
def init_decrease_field_visibility(self):
pass
def init_decrease_method_visibility(self):
pass
def init_increase_field_visibility(self):
pass
def init_increase_method_visibility(self):
pass
def init_extract_interface(self):
pass
def generate_population(self):
"""
Generate population abstract method
"""
pass
def select_random(self):
"""
Randomly selects a refactoring. If there are no candidates it tries again!
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
initializer = random.choice(self.initializers)
logger.debug(f'>>> Randomly selected refactoring: {initializer.__name__}')
main_function, params, name = handle_index_error(initializer)()
if main_function is None:
print(f'Inside the select_random method {name}')
return self.select_random()
else:
return main_function, params, name
def dump_population(self, path=None):
if self.population is None or len(self.population) == 0:
return
population_trimmed = []
for chromosome in self.population:
chromosome_new = []
for gene_ in chromosome:
chromosome_new.append((gene_[2], gene_[1]))
population_trimmed.append(chromosome_new)
# config.logger.debug(population_trimmed)
with open(path, mode='w', encoding='utf-8') as fp:
json.dump(population_trimmed, fp, indent=4)
config.logger.debug(f'The initial population was saved into {path}')
def load_population(self, path=None):
if len(self.population) > 0:
return
with open(path, 'r', encoding='utf-8') as fp:
population_trimmed = json.load(fp)
for chromosome in population_trimmed:
chromosome_new = []
for gene_ in chromosome:
chromosome_new.append((REFACTORING_MAIN_MAP[gene_[0]], gene_[1], gene_[0]))
self.population.append(chromosome_new)
# config.logger.debug(self.population)
config.logger.debug(f'The initial population was loaded into "population field" from {path}')
__init__(self, udb_path, population_size=50, lower_band=10, upper_band=50)
special
Parameters:
Name | Type | Description | Default |
---|---|---|---|
udb_path |
str |
Path for understand database file. |
required |
population_size |
int |
The length of population for GA. |
50 |
lower_band |
int |
The minimum length of individual for GA. |
10 |
upper_band |
int |
The maximum length of individual for GA. |
50 |
Returns:
Type | Description |
---|---|
None |
Source code in codart\sbse\initialize.py
def __init__(self, udb_path, population_size=50, lower_band=10, upper_band=50):
"""
Args:
udb_path (str): Path for understand database file.
population_size (int): The length of population for GA.
lower_band (int): The minimum length of individual for GA.
upper_band (int): The maximum length of individual for GA.
Returns:
None
"""
random.seed(None)
self.udb_path = udb_path
self.population_size = population_size
self.lower_band = lower_band
self.upper_band = upper_band
self.population = []
self.initializers = (
self.init_make_field_non_static, # 0
self.init_make_field_static, # 1
self.init_make_method_static, # 2
self.init_make_method_non_static, # 3
self.init_pullup_field, # 4
self.init_move_field, # 5
self.init_move_method, # 6
# self.init_move_method, # 6.2
self.init_move_class, # 7
# self.init_move_class, # 7.2
self.init_push_down_field, # 8
self.init_extract_class, # 9
# self.init_extract_class, # 9.2
self.init_pullup_method, # 10
self.init_push_down_method, # 11
self.init_pullup_constructor, # 12
self.init_decrease_field_visibility, # 13
self.init_increase_field_visibility, # 14
self.init_decrease_method_visibility, # 15
self.init_increase_method_visibility, # 16
self.init_extract_interface, # 17
# self.init_extract_interface, # 17.2
# self.init_extract_method, # 18
)
self._variables = self.get_all_variables()
self._static_variables = self.get_all_variables(static=True)
self._methods = self.get_all_methods()
self._static_methods = self.get_all_methods(static=True)
self._pullup_field_candidates = self.find_pullup_field_candidates()
self._push_down_field_candidates = self.find_push_down_field_candidates()
self._pullup_method_candidates = self.find_pullup_method_candidates()
self._pullup_constructor_candidates = self.find_pullup_constructor_candidates()
self._push_down_method_candidates = self.find_push_down_method_candidates()
self._extract_interface_candidates = self.find_extract_interface_candidate()
generate_population(self)
Generate population abstract method
Source code in codart\sbse\initialize.py
def generate_population(self):
"""
Generate population abstract method
"""
pass
select_random(self)
Randomly selects a refactoring. If there are no candidates it tries again!
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def select_random(self):
"""
Randomly selects a refactoring. If there are no candidates it tries again!
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
initializer = random.choice(self.initializers)
logger.debug(f'>>> Randomly selected refactoring: {initializer.__name__}')
main_function, params, name = handle_index_error(initializer)()
if main_function is None:
print(f'Inside the select_random method {name}')
return self.select_random()
else:
return main_function, params, name
RandomInitialization (Initialization)
Use to randomly initialize the refactoring population in search-based algorithms
Source code in codart\sbse\initialize.py
class RandomInitialization(Initialization):
"""
Use to randomly initialize the refactoring population in search-based algorithms
"""
def __init__(self, *args, **kwargs):
super(RandomInitialization, self).__init__(*args, **kwargs)
def generate_population(self):
"""
Generate randomly (unbiased) initialized refactoring population
Returns:
list: List of refactoring sequences (list of refactoring operations)
"""
config.logger.debug(f'Generating a random initial population ...')
# population = []
for _ in range(self.population_size):
individual = []
individual_size = random.randint(self.lower_band, self.upper_band)
for j in range(individual_size):
main, params, name = self.select_random()
individual.append((main, params, name))
logger.debug(f'Append a refactoring "{name}" to "{j}th" gene of the individual {_}.')
logger.debug('-' * 100)
self.population.append(individual)
logger.debug(f'Append individual {_} to population, s')
logger.debug('=' * 100)
initial_pop_path = f'{config.PROJECT_LOG_DIR}initial_population_{config.global_execution_start_time}.json'
self.dump_population(path=initial_pop_path)
config.logger.debug(f'Generating a random initial population was finished.')
return self.population
def init_make_field_non_static(self):
"""
Finds all static fields and randomly chooses one of them
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = make_field_non_static.main
params = {"udb_path": self.udb_path}
candidates = self._static_variables
params.update(random.choice(candidates))
params.pop("source_package")
return refactoring_main, params, 'Make Field Non-Static'
def init_make_field_static(self):
"""
Finds all non-static fields and randomly chooses one of them
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = make_field_static.main
params = {"udb_path": self.udb_path}
candidates = self._variables
params.update(random.choice(candidates))
params.pop("source_package")
return refactoring_main, params, 'Make Field Static'
def init_make_method_static(self):
"""
Finds all non-static methods and randomly chooses one of them
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = make_method_static2.main
params = {"udb_path": self.udb_path}
candidates = self._methods
params.update(random.choice(candidates))
params.pop("source_package")
return refactoring_main, params, 'Make Method Static'
def init_make_method_non_static(self):
"""
Finds all static methods and randomly chooses one of them
Returns:
tuple: refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = make_method_non_static2.main
params = {"udb_path": self.udb_path}
candidates = self._static_methods
params.update(random.choice(candidates))
params.pop("source_package")
return refactoring_main, params, 'Make Method Non-Static'
def init_pullup_field(self):
"""
Find all classes with their attributes and package names, then chooses randomly one of them!
Returns:
Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pullup_field.main
# params = {"project_dir": str(Path(self.udb_path).parent)}
params = {"project_dir": config.PROJECT_PATH}
candidates = self._pullup_field_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Pull Up Field'
def init_push_down_field(self):
"""
Finds fields to be push-down
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pushdown_field2.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = self._push_down_field_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Push Down Field'
def init_pullup_method(self):
"""
Finds methods to be pulled-up
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pullup_method.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = self._pullup_method_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Pull Up Method'
def init_pullup_constructor(self):
"""
Finds statements in class constructors to be pulled-up
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pullup_constructor.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = self._pullup_constructor_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Pull Up Constructor'
def init_push_down_method(self):
"""
Finds methods to be pushed-downs
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pushdown_method.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = self._push_down_method_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Push Down Method'
def init_move_field(self):
"""
Finds fields with a class to move
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = move_field.main
params = {"udb_path": str(Path(self.udb_path))}
random_field = random.choice(self._variables)
params.update(random_field)
classes = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
random_class = (random.choice(classes)).longname().split(".")
target_package = None
"""
target_class: str, target_package: str,
"""
if len(random_class) == 1:
target_class = random_class[0]
elif len(random_class) > 1:
target_package = '.'.join(random_class[:-1])
target_class = random_class[-1]
else:
return self.init_move_field()
params.update({
"target_class": target_class,
"target_package": target_package
})
_db.close()
return refactoring_main, params, 'Move Field'
def init_move_field2(self):
"""
Finds fields with a class to move (version 2)
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = move_field.main
params = {"udb_path": str(Path(self.udb_path))}
classes_fields = []
random_field = random.choice(classes_fields)
params.update(random_field)
related_entities = random_field.ents(
"Set, Setby, Contain, Containin, Use, Useby, Create, Createby, DotRef, DotRefby, Define, Definein",
"Type ~Unknown ~Anonymous"
# "Package"
)
print('Parameters', params)
print("related_entities", related_entities)
for e in related_entities:
print(e.longname(), e.kind())
if related_entities is not None and len(related_entities) > 0:
selected_entity = random.choice(related_entities)
package_list = selected_entity.ents('Containin', 'Java Package')
while not package_list and selected_entity.parent() is not None:
package_list = selected_entity.parent().ents('Containin', 'Java Package')
selected_entity = selected_entity.parent()
if len(package_list) < 1:
params.update({"target_package": "(Unnamed_Package)"})
else:
params.update({"target_package": package_list[0].longname()})
def init_move_method(self):
"""
Finds methods with a class to move
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = move_method.main
params = {"udb_path": str(Path(self.udb_path))}
random_method = random.choice(self._methods)
params.update(random_method)
classes = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
random_class = (random.choice(classes)).longname().split(".")
target_package = None
"""
target_class: str, target_package: str,
"""
if len(random_class) == 1:
target_class = random_class[0]
elif len(random_class) > 1:
target_package = '.'.join(random_class[:-1])
target_class = random_class[-1]
else:
return self.init_move_field()
params.update({
"target_class": target_class,
"target_package": target_package
})
_db.close()
return refactoring_main, params, 'Move Method'
def init_move_class(self):
"""
Finds a class which should be moved to another existing package
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = move_class.main
params = {"udb_path": str(Path(self.udb_path))}
classes = _db.ents("Java Class Public ~TypeVariable ~Anonymous ~Unknown ~Unresolved ~Private ~Static")
selected_class = random.choice(classes)
package_list = selected_class.ents('Containin', 'Java Package')
while not package_list and selected_class.parent() is not None:
package_list = selected_class.parent().ents('Containin', 'Java Package')
selected_class = selected_class.parent()
# print(package_list)
params.update({"class_name": selected_class.simplename()})
if len(package_list) < 1:
params.update({"source_package": "(Unnamed_Package)"})
else:
params.update({"source_package": package_list[0].longname()})
entity_filter = "Import, Importby, Contain, Containin, Couple, Coupleby, "
entity_filter += "Create, Createby, DotRef, DotRefby, Declare, Declarein, Define, Definein"
related_entities = selected_class.ents(
entity_filter,
"Type ~Unknown ~Anonymous"
# "Package"
)
# print('Parameters', params)
# print("related_entities", related_entities)
# for e in related_entities:
# print(e.longname(), e.kind())
trials = 0
while trials < 25:
if related_entities is not None and len(related_entities) > 0:
selected_entity = random.choice(related_entities)
package_list = selected_entity.ents('Containin', 'Java Package')
while not package_list and selected_entity.parent() is not None:
package_list = selected_entity.parent().ents('Containin', 'Java Package')
selected_entity = selected_entity.parent()
if len(package_list) < 1:
params.update({"target_package": "(Unnamed_Package)"})
else:
params.update({"target_package": package_list[0].longname()})
else:
packages = _db.ents("Package ~Unknown ~Unresolved ~Unnamed")
if packages is not None and len(packages) > 0:
selected_package = random.choice(packages)
params.update({"target_package": selected_package.longname()})
else:
params.update({"target_package": "(Unnamed_Package)"})
# print(params['source_package'], params['target_package'])
if params['source_package'] != params['target_package'] and params['target_package'] != '(Unnamed_Package)':
break
trials += 1
_db.close()
return refactoring_main, params, 'Move Class'
def init_extract_class(self):
"""
Finds a set of methods and fields which should be extracted as a new class
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = extract_class.main
params = {"udb_path": str(Path(self.udb_path))}
classes = _db.ents("Type Class ~Unknown ~Anonymous")
random_class = random.choice(classes)
params.update(
{
"source_class": random_class.simplename(),
"file_path": random_class.parent().longname()
}
)
class_fields = []
class_methods = []
for ref in random_class.refs("define", "variable"):
class_fields.append(ref.ent())
for ref in random_class.refs("define", "method"):
class_methods.append(ref.ent())
params.update(
{
"moved_fields": [ent.simplename() for ent in
random.sample(class_fields, random.randint(0, len(class_fields)))],
"moved_methods": [ent.simplename() for ent in
random.sample(class_methods, random.randint(0, len(class_methods)))],
}
)
_db.close()
return refactoring_main, params, 'Extract Class'
def init_extract_method(self):
pass
def init_extract_interface(self):
"""
Finds a class which should have an interface
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = extract_interface2.main
# params = {"udb_path": str(Path(self.udb_path))}
random_class = random.choice(self._extract_interface_candidates)
params = {'class_path': random_class}
return refactoring_main, params, 'Extract Interface'
def init_increase_field_visibility(self):
"""
Finds a private field to increase its visibility to public.
Returns:
tuple: Refactoring main func, its parameters, and its human-readable name.
"""
refactoring_main = increase_field_visibility.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = list(filter(lambda d: d['is_public'] is False, self._variables))
field = random.choice(candidates)
params.update({
"source_package": field["source_package"],
"source_class": field["source_class"],
"source_field": field["field_name"],
})
return refactoring_main, params, 'Increase Field Visibility'
def init_decrease_field_visibility(self):
"""
Finds a none-external-reference-public field to decrease its visibility to private.
Returns:
tuple: Refactoring main func, its parameters, and its human-readable name.
"""
refactoring_main = decrease_field_visibility.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = list(filter(lambda d: d['is_private'] is False and d['external_references'] == 0, self._variables))
# print(candidates)
field = random.choice(candidates)
params.update({
"source_package": field["source_package"],
"source_class": field["source_class"],
"source_field": field["field_name"],
})
return refactoring_main, params, 'Decrease Field Visibility'
def init_increase_method_visibility(self):
"""
Finds a private method to increase its visibility to public.
Returns:
tuple: Refactoring main func, its parameters, and its human-readable name.
"""
refactoring_main = increase_method_visibility.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = list(filter(lambda d: d['is_public'] is False, self._methods))
method = random.choice(candidates)
params.update({
"source_package": method["source_package"],
"source_class": method["source_class"],
"source_method": method["method_name"],
})
return refactoring_main, params, 'Increase Method Visibility'
def init_decrease_method_visibility(self):
"""
Finds a none-external-reference-public method to decrease its visibility to private.
Returns:
tuple: Refactoring main func, its parameters, and its human-readable name.
"""
refactoring_main = decrease_method_visibility.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = list(filter(lambda d: d['is_private'] is False and d['external_references'] == 0, self._methods))
method = random.choice(candidates)
params.update({
"source_package": method["source_package"],
"source_class": method["source_class"],
"source_method": method["method_name"],
})
return refactoring_main, params, 'Decrease Method Visibility'
generate_population(self)
Generate randomly (unbiased) initialized refactoring population
Returns:
Type | Description |
---|---|
list |
List of refactoring sequences (list of refactoring operations) |
Source code in codart\sbse\initialize.py
def generate_population(self):
"""
Generate randomly (unbiased) initialized refactoring population
Returns:
list: List of refactoring sequences (list of refactoring operations)
"""
config.logger.debug(f'Generating a random initial population ...')
# population = []
for _ in range(self.population_size):
individual = []
individual_size = random.randint(self.lower_band, self.upper_band)
for j in range(individual_size):
main, params, name = self.select_random()
individual.append((main, params, name))
logger.debug(f'Append a refactoring "{name}" to "{j}th" gene of the individual {_}.')
logger.debug('-' * 100)
self.population.append(individual)
logger.debug(f'Append individual {_} to population, s')
logger.debug('=' * 100)
initial_pop_path = f'{config.PROJECT_LOG_DIR}initial_population_{config.global_execution_start_time}.json'
self.dump_population(path=initial_pop_path)
config.logger.debug(f'Generating a random initial population was finished.')
return self.population
init_decrease_field_visibility(self)
Finds a none-external-reference-public field to decrease its visibility to private.
Returns:
Type | Description |
---|---|
tuple |
Refactoring main func, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_decrease_field_visibility(self):
"""
Finds a none-external-reference-public field to decrease its visibility to private.
Returns:
tuple: Refactoring main func, its parameters, and its human-readable name.
"""
refactoring_main = decrease_field_visibility.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = list(filter(lambda d: d['is_private'] is False and d['external_references'] == 0, self._variables))
# print(candidates)
field = random.choice(candidates)
params.update({
"source_package": field["source_package"],
"source_class": field["source_class"],
"source_field": field["field_name"],
})
return refactoring_main, params, 'Decrease Field Visibility'
init_decrease_method_visibility(self)
Finds a none-external-reference-public method to decrease its visibility to private.
Returns:
Type | Description |
---|---|
tuple |
Refactoring main func, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_decrease_method_visibility(self):
"""
Finds a none-external-reference-public method to decrease its visibility to private.
Returns:
tuple: Refactoring main func, its parameters, and its human-readable name.
"""
refactoring_main = decrease_method_visibility.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = list(filter(lambda d: d['is_private'] is False and d['external_references'] == 0, self._methods))
method = random.choice(candidates)
params.update({
"source_package": method["source_package"],
"source_class": method["source_class"],
"source_method": method["method_name"],
})
return refactoring_main, params, 'Decrease Method Visibility'
init_extract_class(self)
Finds a set of methods and fields which should be extracted as a new class
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_extract_class(self):
"""
Finds a set of methods and fields which should be extracted as a new class
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = extract_class.main
params = {"udb_path": str(Path(self.udb_path))}
classes = _db.ents("Type Class ~Unknown ~Anonymous")
random_class = random.choice(classes)
params.update(
{
"source_class": random_class.simplename(),
"file_path": random_class.parent().longname()
}
)
class_fields = []
class_methods = []
for ref in random_class.refs("define", "variable"):
class_fields.append(ref.ent())
for ref in random_class.refs("define", "method"):
class_methods.append(ref.ent())
params.update(
{
"moved_fields": [ent.simplename() for ent in
random.sample(class_fields, random.randint(0, len(class_fields)))],
"moved_methods": [ent.simplename() for ent in
random.sample(class_methods, random.randint(0, len(class_methods)))],
}
)
_db.close()
return refactoring_main, params, 'Extract Class'
init_extract_interface(self)
Finds a class which should have an interface
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_extract_interface(self):
"""
Finds a class which should have an interface
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = extract_interface2.main
# params = {"udb_path": str(Path(self.udb_path))}
random_class = random.choice(self._extract_interface_candidates)
params = {'class_path': random_class}
return refactoring_main, params, 'Extract Interface'
init_increase_field_visibility(self)
Finds a private field to increase its visibility to public.
Returns:
Type | Description |
---|---|
tuple |
Refactoring main func, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_increase_field_visibility(self):
"""
Finds a private field to increase its visibility to public.
Returns:
tuple: Refactoring main func, its parameters, and its human-readable name.
"""
refactoring_main = increase_field_visibility.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = list(filter(lambda d: d['is_public'] is False, self._variables))
field = random.choice(candidates)
params.update({
"source_package": field["source_package"],
"source_class": field["source_class"],
"source_field": field["field_name"],
})
return refactoring_main, params, 'Increase Field Visibility'
init_increase_method_visibility(self)
Finds a private method to increase its visibility to public.
Returns:
Type | Description |
---|---|
tuple |
Refactoring main func, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_increase_method_visibility(self):
"""
Finds a private method to increase its visibility to public.
Returns:
tuple: Refactoring main func, its parameters, and its human-readable name.
"""
refactoring_main = increase_method_visibility.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = list(filter(lambda d: d['is_public'] is False, self._methods))
method = random.choice(candidates)
params.update({
"source_package": method["source_package"],
"source_class": method["source_class"],
"source_method": method["method_name"],
})
return refactoring_main, params, 'Increase Method Visibility'
init_make_field_non_static(self)
Finds all static fields and randomly chooses one of them
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_make_field_non_static(self):
"""
Finds all static fields and randomly chooses one of them
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = make_field_non_static.main
params = {"udb_path": self.udb_path}
candidates = self._static_variables
params.update(random.choice(candidates))
params.pop("source_package")
return refactoring_main, params, 'Make Field Non-Static'
init_make_field_static(self)
Finds all non-static fields and randomly chooses one of them
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_make_field_static(self):
"""
Finds all non-static fields and randomly chooses one of them
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = make_field_static.main
params = {"udb_path": self.udb_path}
candidates = self._variables
params.update(random.choice(candidates))
params.pop("source_package")
return refactoring_main, params, 'Make Field Static'
init_make_method_non_static(self)
Finds all static methods and randomly chooses one of them
Returns:
Type | Description |
---|---|
tuple |
refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_make_method_non_static(self):
"""
Finds all static methods and randomly chooses one of them
Returns:
tuple: refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = make_method_non_static2.main
params = {"udb_path": self.udb_path}
candidates = self._static_methods
params.update(random.choice(candidates))
params.pop("source_package")
return refactoring_main, params, 'Make Method Non-Static'
init_make_method_static(self)
Finds all non-static methods and randomly chooses one of them
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_make_method_static(self):
"""
Finds all non-static methods and randomly chooses one of them
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = make_method_static2.main
params = {"udb_path": self.udb_path}
candidates = self._methods
params.update(random.choice(candidates))
params.pop("source_package")
return refactoring_main, params, 'Make Method Static'
init_move_class(self)
Finds a class which should be moved to another existing package
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_move_class(self):
"""
Finds a class which should be moved to another existing package
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = move_class.main
params = {"udb_path": str(Path(self.udb_path))}
classes = _db.ents("Java Class Public ~TypeVariable ~Anonymous ~Unknown ~Unresolved ~Private ~Static")
selected_class = random.choice(classes)
package_list = selected_class.ents('Containin', 'Java Package')
while not package_list and selected_class.parent() is not None:
package_list = selected_class.parent().ents('Containin', 'Java Package')
selected_class = selected_class.parent()
# print(package_list)
params.update({"class_name": selected_class.simplename()})
if len(package_list) < 1:
params.update({"source_package": "(Unnamed_Package)"})
else:
params.update({"source_package": package_list[0].longname()})
entity_filter = "Import, Importby, Contain, Containin, Couple, Coupleby, "
entity_filter += "Create, Createby, DotRef, DotRefby, Declare, Declarein, Define, Definein"
related_entities = selected_class.ents(
entity_filter,
"Type ~Unknown ~Anonymous"
# "Package"
)
# print('Parameters', params)
# print("related_entities", related_entities)
# for e in related_entities:
# print(e.longname(), e.kind())
trials = 0
while trials < 25:
if related_entities is not None and len(related_entities) > 0:
selected_entity = random.choice(related_entities)
package_list = selected_entity.ents('Containin', 'Java Package')
while not package_list and selected_entity.parent() is not None:
package_list = selected_entity.parent().ents('Containin', 'Java Package')
selected_entity = selected_entity.parent()
if len(package_list) < 1:
params.update({"target_package": "(Unnamed_Package)"})
else:
params.update({"target_package": package_list[0].longname()})
else:
packages = _db.ents("Package ~Unknown ~Unresolved ~Unnamed")
if packages is not None and len(packages) > 0:
selected_package = random.choice(packages)
params.update({"target_package": selected_package.longname()})
else:
params.update({"target_package": "(Unnamed_Package)"})
# print(params['source_package'], params['target_package'])
if params['source_package'] != params['target_package'] and params['target_package'] != '(Unnamed_Package)':
break
trials += 1
_db.close()
return refactoring_main, params, 'Move Class'
init_move_field(self)
Finds fields with a class to move
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_move_field(self):
"""
Finds fields with a class to move
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = move_field.main
params = {"udb_path": str(Path(self.udb_path))}
random_field = random.choice(self._variables)
params.update(random_field)
classes = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
random_class = (random.choice(classes)).longname().split(".")
target_package = None
"""
target_class: str, target_package: str,
"""
if len(random_class) == 1:
target_class = random_class[0]
elif len(random_class) > 1:
target_package = '.'.join(random_class[:-1])
target_class = random_class[-1]
else:
return self.init_move_field()
params.update({
"target_class": target_class,
"target_package": target_package
})
_db.close()
return refactoring_main, params, 'Move Field'
init_move_field2(self)
Finds fields with a class to move (version 2)
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_move_field2(self):
"""
Finds fields with a class to move (version 2)
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = move_field.main
params = {"udb_path": str(Path(self.udb_path))}
classes_fields = []
random_field = random.choice(classes_fields)
params.update(random_field)
related_entities = random_field.ents(
"Set, Setby, Contain, Containin, Use, Useby, Create, Createby, DotRef, DotRefby, Define, Definein",
"Type ~Unknown ~Anonymous"
# "Package"
)
print('Parameters', params)
print("related_entities", related_entities)
for e in related_entities:
print(e.longname(), e.kind())
if related_entities is not None and len(related_entities) > 0:
selected_entity = random.choice(related_entities)
package_list = selected_entity.ents('Containin', 'Java Package')
while not package_list and selected_entity.parent() is not None:
package_list = selected_entity.parent().ents('Containin', 'Java Package')
selected_entity = selected_entity.parent()
if len(package_list) < 1:
params.update({"target_package": "(Unnamed_Package)"})
else:
params.update({"target_package": package_list[0].longname()})
init_move_method(self)
Finds methods with a class to move
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_move_method(self):
"""
Finds methods with a class to move
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
_db = und.open(self.udb_path)
refactoring_main = move_method.main
params = {"udb_path": str(Path(self.udb_path))}
random_method = random.choice(self._methods)
params.update(random_method)
classes = _db.ents("Class ~Unknown ~Anonymous ~TypeVariable ~Private ~Static")
random_class = (random.choice(classes)).longname().split(".")
target_package = None
"""
target_class: str, target_package: str,
"""
if len(random_class) == 1:
target_class = random_class[0]
elif len(random_class) > 1:
target_package = '.'.join(random_class[:-1])
target_class = random_class[-1]
else:
return self.init_move_field()
params.update({
"target_class": target_class,
"target_package": target_package
})
_db.close()
return refactoring_main, params, 'Move Method'
init_pullup_constructor(self)
Finds statements in class constructors to be pulled-up
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_pullup_constructor(self):
"""
Finds statements in class constructors to be pulled-up
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pullup_constructor.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = self._pullup_constructor_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Pull Up Constructor'
init_pullup_field(self)
Find all classes with their attributes and package names, then chooses randomly one of them!
Returns:
Type | Description |
---|---|
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_pullup_field(self):
"""
Find all classes with their attributes and package names, then chooses randomly one of them!
Returns:
Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pullup_field.main
# params = {"project_dir": str(Path(self.udb_path).parent)}
params = {"project_dir": config.PROJECT_PATH}
candidates = self._pullup_field_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Pull Up Field'
init_pullup_method(self)
Finds methods to be pulled-up
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_pullup_method(self):
"""
Finds methods to be pulled-up
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pullup_method.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = self._pullup_method_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Pull Up Method'
init_push_down_field(self)
Finds fields to be push-down
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_push_down_field(self):
"""
Finds fields to be push-down
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pushdown_field2.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = self._push_down_field_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Push Down Field'
init_push_down_method(self)
Finds methods to be pushed-downs
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_push_down_method(self):
"""
Finds methods to be pushed-downs
Returns:
tuple: Refactoring main method, its parameters, and its human-readable name.
"""
refactoring_main = pushdown_method.main
params = {"udb_path": str(Path(self.udb_path))}
candidates = self._push_down_method_candidates
params.update(random.choice(candidates))
return refactoring_main, params, 'Push Down Method'
SmellInitialization (RandomInitialization)
Use to initialize refactoring population based on refactoring opportunities
Source code in codart\sbse\initialize.py
class SmellInitialization(RandomInitialization):
"""
Use to initialize refactoring population based on refactoring opportunities
"""
def __init__(self, *args, **kwargs):
"""
Returns:
SmellInitialization: An instance of SmellInitialization class
"""
super(SmellInitialization, self).__init__(*args, **kwargs)
# Load csv files
self.move_method_candidates = self.load_move_method_candidates()
self.extract_class_candidates = self.load_extract_class_candidates()
# self.extract_method_candidates = self.load_extract_method_candidates() # We leave extract method for now.
def generate_population(self):
"""
Generate a biased initial population consists of first-time validated refactorings
Return:
list: list of refactoring sequences (list of refactoring operations)
"""
config.logger.debug(f'Generating a biased initial population ...')
for _ in range(0, self.population_size):
individual = []
individual_size = random.randint(self.lower_band, self.upper_band)
for j in range(individual_size):
main, params, name = self.select_random()
logger.debug(f'Refactoring name: {name}')
logger.debug(f'Refactoring params: {params}')
is_correct_refactoring = main(**params)
while is_correct_refactoring is False:
reset_project()
main, params, name = self.select_random()
logger.debug(f'Refactoring name: {name}')
logger.debug(f'Refactoring params: {params}')
is_correct_refactoring = main(**params)
####
# update_understand_database(self.udb_path)
# quit()
####
individual.append((main, params, name))
logger.debug(f'Append a refactoring "{name}" to "{j}th" gene of the individual {_}.')
reset_project()
logger.debug('-' * 100)
self.population.append(individual)
logger.debug(f'Append individual {_} to population, s')
logger.debug('=' * 100)
initial_pop_path = f'{config.PROJECT_LOG_DIR}initial_population_{config.global_execution_start_time}.json'
self.dump_population(path=initial_pop_path)
config.logger.debug(f'Generating a biased initial population was finished.')
return self.population
def load_extract_class_candidates(self):
_db = und.open(self.udb_path)
god_classes = pandas.read_csv(config.GOD_CLASS_PATH, sep="\t")
candidates = []
for index, row in god_classes.iterrows():
moved_fields, moved_methods = [], []
# print(row[0].strip())
try:
class_file = _db.lookup(re.compile(row[0].strip() + r'$'), "Class")[0].parent().longname()
# print(class_file)
except:
# print('Class file not found')
continue
source_class = row[0].split(".")[-1]
data = row[1][1:-1] # skip [ and ]
data = data.split(",")
for field_or_method in data:
field_or_method = field_or_method.strip()
if "(" in field_or_method:
# Method
moved_methods.append(
field_or_method.split("::")[1].split("(")[0]
)
elif len(field_or_method.split(" ")) == 2:
# Field
moved_fields.append(
field_or_method.split(" ")[-1]
)
candidates.append(
{
"source_class": source_class,
"moved_fields": moved_fields,
"moved_methods": moved_methods,
"file_path": class_file
}
)
# print(candidates)
# quit()
_db.close()
return candidates
def load_move_method_candidates(self):
feature_envies = pandas.read_csv(
config.FEATURE_ENVY_PATH, sep=None, engine='python'
)
candidates = []
for index, row in feature_envies.iterrows():
source_package, source_class, method_name = get_move_method_location(row[1])
target_info = row[2].split(".")
target_package = ".".join(target_info[:-1])
target_class = target_info[-1]
candidates.append({
"source_package": source_package,
"source_class": source_class,
"method_name": method_name,
"target_package": target_package,
"target_class": target_class
})
return candidates
def load_extract_method_candidates(self):
_db = und.open(self.udb_path)
long_methods = pandas.read_csv(
config.LONG_METHOD_PATH, sep='\t', engine='python'
)
candidates = []
for index, row in long_methods.iterrows():
lines = {}
class_info = row[0].strip().split(".")[-1]
class_file = _db.lookup(class_info + ".java", "File")
if class_file:
class_file = class_file[0].longname()
else:
continue
_bytes = open(class_file, mode='rb').read()
file_content = codecs.decode(_bytes, errors='strict')
lines_info = row[5]
for i in lines_info.split(")"):
if i == '':
continue
values = i.split(",")
char_number = values[0][1:].strip()
length = values[1].strip()
should_copy = False if values[2].strip() == 'F' else True
if char_number and length:
char_number = int(char_number)
length = char_number + int(length)
start = len(file_content[:char_number].split("\n"))
stop = len(file_content[:length].split("\n"))
for line in range(start, stop + 1):
lines[line] = should_copy
candidates.append({
"file_path": class_file,
"lines": lines
})
_db.close()
return candidates
def init_move_method(self):
params = random.choice(self.move_method_candidates)
params["udb_path"] = self.udb_path
main = move_method.main
# print(params)
return main, params, "Move Method"
def init_extract_class(self):
main = extract_class.main
params = random.choice(self.extract_class_candidates)
params["udb_path"] = self.udb_path
return main, params, "Extract Class"
def init_extract_method(self):
main = extract_method.main
params = random.choice(self.extract_method_candidates)
params["udb_path"] = self.udb_path
return main, params, "Extract Method"
__init__(self, *args, **kwargs)
special
Returns:
Type | Description |
---|---|
SmellInitialization |
An instance of SmellInitialization class |
Source code in codart\sbse\initialize.py
def __init__(self, *args, **kwargs):
"""
Returns:
SmellInitialization: An instance of SmellInitialization class
"""
super(SmellInitialization, self).__init__(*args, **kwargs)
# Load csv files
self.move_method_candidates = self.load_move_method_candidates()
self.extract_class_candidates = self.load_extract_class_candidates()
# self.extract_method_candidates = self.load_extract_method_candidates() # We leave extract method for now.
generate_population(self)
Generate a biased initial population consists of first-time validated refactorings
Returns:
Type | Description |
---|---|
list |
list of refactoring sequences (list of refactoring operations) |
Source code in codart\sbse\initialize.py
def generate_population(self):
"""
Generate a biased initial population consists of first-time validated refactorings
Return:
list: list of refactoring sequences (list of refactoring operations)
"""
config.logger.debug(f'Generating a biased initial population ...')
for _ in range(0, self.population_size):
individual = []
individual_size = random.randint(self.lower_band, self.upper_band)
for j in range(individual_size):
main, params, name = self.select_random()
logger.debug(f'Refactoring name: {name}')
logger.debug(f'Refactoring params: {params}')
is_correct_refactoring = main(**params)
while is_correct_refactoring is False:
reset_project()
main, params, name = self.select_random()
logger.debug(f'Refactoring name: {name}')
logger.debug(f'Refactoring params: {params}')
is_correct_refactoring = main(**params)
####
# update_understand_database(self.udb_path)
# quit()
####
individual.append((main, params, name))
logger.debug(f'Append a refactoring "{name}" to "{j}th" gene of the individual {_}.')
reset_project()
logger.debug('-' * 100)
self.population.append(individual)
logger.debug(f'Append individual {_} to population, s')
logger.debug('=' * 100)
initial_pop_path = f'{config.PROJECT_LOG_DIR}initial_population_{config.global_execution_start_time}.json'
self.dump_population(path=initial_pop_path)
config.logger.debug(f'Generating a biased initial population was finished.')
return self.population
init_extract_class(self)
Finds a set of methods and fields which should be extracted as a new class
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_extract_class(self):
main = extract_class.main
params = random.choice(self.extract_class_candidates)
params["udb_path"] = self.udb_path
return main, params, "Extract Class"
init_move_method(self)
Finds methods with a class to move
Returns:
Type | Description |
---|---|
tuple |
Refactoring main method, its parameters, and its human-readable name. |
Source code in codart\sbse\initialize.py
def init_move_method(self):
params = random.choice(self.move_method_candidates)
params["udb_path"] = self.udb_path
main = move_method.main
# print(params)
return main, params, "Move Method"