Implementing Swift Local Refactoring action.
Part 2 of 2.
In the previous part we’ve implemented
The very same
findNestedIfStatements can be reused to implement refactoring transformation.
The first thing to do is check if refactoring can be applicable.
Note that we return
true to abort the refactoring transformation.
Next we create a buffer to write transformed code into and then create an output stream for writing to the buffer.
A collapsed if statement will still be an if statement, so we write the
if keyword to output stream using
kw_if keyword token.
Now we need to write the combined conditions list to output stream.
Conveniently, conditions in the condition-list can be joined together using commas.
Grammar of an if statement
if-statement → if condition-list code-block else-clause opt
else-clause → else code-block else if-statement
condition-list → condition condition , condition-list
Loop through conditions collected while finding nested if statements:
Get the range of the condition statement
SC in the original source code:
Get the string representation of the condition statement from the original source code:
SM here is an instance of
SourceManager available to each refactoring action implementation.
Finally write the condition string into output stream joining it with the comma if needed.
On first iteration separator will be an empty string while 2nd and consequent statements are joined by
", " string.
Now is the time to write the then statement shared by all collapsed if statements.
This is the reason we saved
LastThenStatement while finding nested if statements.
Again, we get the string representation of the then statement and write it to output stream.
Then statement already contains opening and closing braces (
}), so no need to add those.
By this time the new transformed code is saved to output stream
Final step is to replace original code with the new code using Source Manager
First step is to get the range of the untransformed source code.
Here we take range from the
Start of the
FirstIfStmt to the
End of the then statement.
That range is then transformed into source range, e.g. range in Source Manager
Finally, the code in
SourceRange is replaced with contents of
Buffer and we return
false to indicate successful transformation (🤷♂️)
The implementation is ready to be tested. If anything goes wrong, then it’s time to debug.