Using the Swift 3.0 Converter on a Large Code Base

If you’re like me, you consider every line of code a liability; a potential source of bugs or technical debt. If so, then you will find the Swift 3.0 converter terrifying. Literally every swift source file in your project will be modified, and depending on the type of code in those source files, almost half of the lines in those files could be modified. You’re going to want to have a developer look at every single one of those changes, understand it, and determine if a better change could be made, or if the change is even necessary.

For a sense of how invasive the Swift 3 converter tool is, I ran it on our main codebase. 27 minutes later:

$ git diff --stat
204 files changed, 4643 insertions(+), 4559 deletions(-)

Obviously, getting that many changes reviewed is going to take a coordinated effort, so I wanted to come up with a process that would allow our team to share the load without duplicating work or stepping on each other’s toes.

Before using the conversion tool, you may want to remove any conditional compiles based on swift version. We had converted our code base to Swift 2.3 and used conditional compiles to support building on both Xcode 7 and 8. Swift 3 is too different to reasonably maintain it simultaneously with older versions, so I would recommend doing a find all for `#if swift` and removing any code for older versions of Swift.

Next, you don’t want everyone running the conversion tool because that’s a waste of time. You also don’t want to review the actual edits within the conversion tool preview, as it does not save interim progress. Any edits made in the preview are lost if Xcode crashes or if the dialog is cancelled. You might be thinking, “of course, just don’t cancel the dialog,” but I’d remind you that the keyboard shortcut for autocomplete is the escape key, and it’s actually very easy to lose a few hours of work that way, even though that’s totally not something that I did because that would be dumb and embarrassing.

After running the tool I added a comment to the top of each swift source file that was modified with this terminal command run from ${SRCROOT}:

$ find . \( -name "*.swift" \) -exec sed -i '' -e '1 i\
// SWIFTREVIEW: Automatic swift migration must be vetted by a human' {} ";"

Then, I added a script build phase to the target to flag each of these comments as a warning:

echo "searching ${SRCROOT} for ${TAGS}"
find "${SRCROOT}" \( -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\$" | perl -p -e "s/($TAGS)/ warning: \$1/"

Now, the converted source can be committed, and everyone can begin the task of verifying the changes. If your code is of a certain level of complexity there’s a good chance the result won’t even compile, so files that are generating errors should be given top priority.

When a developer reviews a file, they can use Xcode’s Comparison view and see all the changes made by the conversion tool just as easily as if they had run the converter themselves. I would recommend not allowing any commits to files that still have the SWIFTREVIEW tag, just to make it easier to review the changes made by the conversion tool in isolation.

Once the developer is willing to sign off on the changes, they can just delete the comment and commit the result.

The warning could be converted to an error after a predetermined amount of time just to show that you’re serious. Once every file has been checked and all the SWIFTREVIEW comments have been removed the build phase can be removed as well.