Swift Refactoring - Implementation - Part 2

Implementing Swift Local Refactoring action.

Part 2 of 2.

In the previous part we’ve implemented isApplicable check.

The very same findNestedIfStatements can be reused to implement refactoring transformation.

// 1 The first thing to do is check if refactoring can be applicable. Note that we return true to abort the refactoring transformation.

// 2 Next we create a buffer to write transformed code into and then create an output stream for writing to the buffer.

// 3 A collapsed if statement will still be an if statement, so we write the if keyword to output stream using kw_if keyword token.

// 4 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.

// 5 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 ({ and }), so no need to add those.

// 6 By this time the new transformed code is saved to output stream OS. Final step is to replace original code with the new code using Source Manager SM.

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 SM’s coordinates:

Finally, the code in SourceRange is replaced with contents of Buffer and we return false to indicate successful transformation (🤷‍♂️)

Full version of Refactoring.cpp.

The implementation is ready to be tested. If anything goes wrong, then it’s time to debug.


Next - Debugging

Published: February 04 2019

blog comments powered by Disqus