Refactoring code that uses the PreProcessor

I got to go to great presentation today about work being done on providing refactorings for C code that get runs through a preprocessor.  The presentation covered three interesting areas where refactoring gets difficult and presented high level overviews of how to address each situation.  Specifically: conditional compilation regions, macros and #include’s.  Conditional compilation (#if and #ifdef’s) make things extremely interesting because it causes a potentially exponential increase in the number of meanings behind your code (consider nested #if’s).  On top of that you can have a conditional section which includes no valid code whatsoever. Consider the coder who writes:

 

#if some_random_name

      Now here’s where I explain what this code is doing. I could

      a comment, but really I prefer to just use conditionals.

#else

      int a = 0;

#endif

 

When trying to do a refactoring, how do you tell that the “else” is a branch that should be considered as part of the refactoring, while the “if” is not.

 

With macros you run into all sorts of difficult issues.  Say, for example, I have a macro like this:

 

#define MAKE_ENUM(name) struct name { enum _Enum { }; }; typedef name::_Enum name##Enum;

 

And I have the following code that uses it:

 

MAKE_ENUM(TypeAttributes)

TypeAttributesEnum attr;

 

And I then rename “TypeAttributesEnum” to “MemberAttributesEnum”.  You need to be able to go and analyze the macro and realize that in order to get the name change you’ll need to change the macro call to MAKE_ENUM(MemberAttributes).

 

I bring this up because this is an area where refactorings in VS2k5 are pretty weak.  If you have conditional sections in your code then we’ll basically only understand one code path that goes through it all.  We’ll refactor accurately through that path, but if you later change your project or compiler setup to change which sections are conditionally brought in (say because you’ve switch your configuration from debug to release). 

 

This is probably something that we’re not going to improve on in this release.  Because of the large cost to implanting support for this, and also the feeling that conditional compilation is not something that majority of our customers do we felt it could wait until a later release.  However, until then we have to admit that our current refactorings will not provide the complete correctness that you would want on the C# code that some customers will be writing.