Refactoring is useful, we all know that, but how to refactor in the presence of #ifdefs? Existing systems do something like this:
Here, the rename refactoring introduces an error, because not all configs are refactored correctly.
Sometimes, even the behavior is changed:
Ifdefs are used commonly in product lines, and we want to know for given refactorings that they do not change the behavior of any of the variants.
First, Jorg looked at how existing systems for refactoring handle this
1) Some systems do not support real refactorings, they are more like ‘find and replace’ and hence do not check anything
2) Some refactoring tools only work on one variant, and threat the other variants as commented out (Netbeans, XCode, Eclipse CDT)
3) Other system work variant-based: they try to apply the refactoring to each variant in isolation and then transfer the results back. But, that does not scale so well for large systems (XRefactoring, CScout)
4) There are tools that have built-in support for variants, but they do not support all, and, more importantly, they require you to annotate your code, introducing manual work.
5) The final strategy is an improvement of number 4, using heuristics to reason about configuration options.
To summarize, refactoring engines in practice are not able to support refactoring variable systems well enough.
So, Jorg and his team created a tool that can do this: Morpheus. Requirements: it needs to scale and keep all variants the same.
They used variability aware parsing (Kastner, OOPSLA ’11) and variability aware control flow graphs (Liebig FSE ’13, Walkingshaw, Onward ’14)
This raises questions though, like: is a given configuration option dead. Sat to the rescue! Jorg coded these problems into a sat and applied a SAT solver.
To see if Morpheus really works, they applied it on three case studies: BusyBox, OpenSLL and SQLLite with 792, 589 and 93 different configuration options respectively. Of course, not all these variants are needed, but you do not know this when refactoring, you want to be sure all stay the same.
On the three systems, Jorg executes 11,500 refactorings and he found no errors (failing tests)