Pull-up method
Introduction
When subclasses grow and get developed separately, your code may have methods that perform similar work. Pull up method refactoring removes the repetitive method from subclasses and moves it to a superclass.
Pre and Post Conditions
Pre Conditions:
-
The source package, class and method should exist.
-
If the method uses attributes and methods that are defined in the body of the classes, The refactoring should not be implemented.
Post Conditions:
No specific Post Condition
pullup_method_refactoring(source_filenames, package_name, class_name, method_key, filename_mapping=<function <lambda> at 0x0000015D7484B8B0>)
The main function that does the process of pull up method refactoring. Removes the necessary methods from the subclasses and moves them to a superclass.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
source_filenames |
list |
A list of file names to be processed |
required |
package_name |
str |
The name of the package in which the refactoring has to be done(contains the classes) |
required |
class_name |
str |
Name of the class in which the refactoring has to be done (pulling up the field from here) |
required |
method_key |
str |
Name of the method which needs to be removed from the subclasses/pulled up |
required |
filename_mapping |
str |
Mapping the file's name to the correct format so that it can be processed |
<function <lambda> at 0x0000015D7484B8B0> |
Returns:
Type | Description |
---|---|
|
No returns |
Source code in refactorings\pullup_method.py
def pullup_method_refactoring(source_filenames: list, package_name: str, class_name: str, method_key: str,
filename_mapping=lambda x: x):
"""The main function that does the process of pull up method refactoring.
Removes the necessary methods from the subclasses and moves them to a superclass.
Args:
source_filenames (list): A list of file names to be processed
package_name (str): The name of the package in which the refactoring has to be done(contains the classes)
class_name (str): Name of the class in which the refactoring has to be done (pulling up the field from here)
method_key (str): Name of the method which needs to be removed from the subclasses/pulled up
filename_mapping (str): Mapping the file's name to the correct format so that it can be processed
Returns:
No returns
"""
program = get_program(source_filenames) # getting the program packages
_sourceclass = program.packages[package_name].classes[class_name]
target_class_name = _sourceclass.superclass_name
static = 0
removemethod = get_removemethods(program, package_name, target_class_name, method_key,
class_name) # Similar methods in other classes
_targetclass = program.packages[package_name].classes[target_class_name]
_method_name = program.packages[package_name].classes[class_name].methods[method_key]
tokens_info = TokensInfo(_method_name.parser_context)
exps = tokens_info.get_token_index(tokens_info.token_stream.tokens, tokens_info.start,
tokens_info.stop) # list of class variables that are used in the method
if _method_name.is_constructor:
return False
# if method use param of class body return false
for token in exps:
if token.text in _sourceclass.fields:
return False
if bool(_method_name.body_method_invocations_without_typename) == True:
return False
Rewriter_ = Rewriter(program, filename_mapping)
for remove in removemethod:
_methodd = removemethod[remove]
if _methodd != None:
_methodds = _methodd[0]
_method = program.packages[package_name].classes[remove].methods[str(_methodds)]
_method_token_info = TokensInfo(_method.parser_context)
Rewriter_.replace(_method_token_info, " ")
class_tokens_info = TokensInfo(_targetclass.parser_context)
singlefileelement = SingleFileElement(_method_name.parser_context, _method_name.filename)
token_stream_rewriter = TokenStreamRewriter(singlefileelement.get_token_stream())
strofmethod = token_stream_rewriter.getText(program_name=token_stream_rewriter.DEFAULT_PROGRAM_NAME,
start=tokens_info.start,
stop=tokens_info.stop)
Rewriter_.insert_before(tokens_info=class_tokens_info, text=strofmethod)
Rewriter_.apply()
# The Method has to be updated anywhere else that it's used
for package_names in program.packages:
package = program.packages[package_names]
for class_ in package.classes:
_class = package.classes[class_]
for method_ in _class.methods:
__method = _class.methods[method_]
for inv in __method.body_method_invocations:
invc = __method.body_method_invocations[inv]
method_name = method_key[:method_key.find('(')]
if (invc[0] == method_name & package_names == package_name):
inv_tokens_info = TokensInfo(inv)
if (static == 0):
class_token_info = TokensInfo(_class.body_context)
Rewriter_.insert_after_start(class_token_info, target_class_name + " " + str.lower(
target_class_name) + "=" + "new " + target_class_name + "();")
Rewriter_.apply()
Rewriter_.replace(inv_tokens_info, target_class_name)
Rewriter_.apply()
return True