In the Visualization Team, we’ve recently started using ReSharper C++ 10.0.2 in Microsoft Visual Studio to assist with writing C++ code. We also have some home-grown (and predictably ugly) C++ preprocessor macros specifically for the Microsoft compiler to help with various code quality issues such as automatic coverage reports, execution profiling, unit test generators and so on. The problem is that when ReSharper parses the C++ source code, it does so with a slightly different “interpretation” of the the C++ preprocessor specification than Microsoft’s compiler and the IntelliSense parser. I’m not going to get involved with any argument as to which is “most correct”; let’s just say that they are different. Different enough that ReSharper complains about our macros, even though the compiler thinks they’re fine. If we could detect when the ReSharper parser is looking at our code, we could simplify the macro definitions and stop ReSharper complaining.
Microsoft Visual Studio helpfully provides a preprocessor macro named ‘__INTELLISENSE__‘ that allows you to detect when it is IntelliSense that is parsing your source code, but I couldn’t find the equivalent for ReSharper. That’s not to say that one doesn’t exist, but I couldn’t find any on-line documentation for one.
However, there obviously is a difference between the Microsoft and JetBrains parsers (otherwise we wouldn’t need to distinguish between them!) so can we use that variation to detect who is parsing our source code? The difference that is causing our macros problems is the way that macro argument tokens are pasted together and joined. Here’s an example:
#define LITERAL(a) a #define JOIN(a,b) LITERAL(a)LITERAL(b) #define BEFOREAFTER 1
The first question is: why aren’t we using the token pasting operator? Ironically, that operator, ‘##‘, solves all our problems (in this case). Therefore it’s not a candidate for distinguishing the two parsers. So, given the macros above, what does the following expand to?
Well, the Microsoft products (as of MSVC 2013) expand it to ‘1‘ whereas ReSharper expands it to two tokens: ‘BEFORE‘ immediately followed by ‘AFTER‘. Fascinating, but not particularly useful, surely? Ah, but consider this:
#if JOIN(BEFORE,AFTER) // We're being parsed by Microsoft products #else // We're being parsed by ReSharper #endif
Inside, the ReSharper parser is no doubt bitterly fuming about the malformed ‘#if‘ condition; but it does so silently and the test condition ultimately fails.
Putting it all together gives us:
#define RESHARPER_LITERAL(a) a #define RESHARPER_JOIN(a,b) RESHARPER_LITERAL(a)RESHARPER_LITERAL(b) #define RESHARPER_DISABLED 1 #if RESHARPER_JOIN(RESHARPER,_DISABLED) #define __RESHARPER__ 0 #else #define __RESHARPER__ 1 #endif #undef RESHARPER_DISABLED #undef RESHARPER_JOIN #undef RESHARPER_LITERAL
Of course, this code snippet is preceded by a huge comment explaining why we’re abusing the preprocessor quite so badly, and suggesting that the reader pretends she never saw it.
Great work! Actually we plan to make R++ fully compatible with VS, so this approach can be broken in the next versions. There is undocumented (but we’re going to document it) macro __RSCPP_VERSION. If you still need R++ detection you can use it.