JetBrains / JetBrains/resharper-unity
Preprocessor defines
- Dominant language
- C#
- Stars
- 1.2k
- Forks
- 142
- PR merge metrics
- No merged PRs in 30d
Description
ReSharper/Rider will parse source code based on the current "context", which is usually the current project configuration - e.g. Debug or Release. As part of that, various preprocessor symbols can be defined - `DEBUG` and `TRACE` are common. Unity will also add symbols such as `UNITY_5_3_OR_NEWER`, `ENABLE_SPRITES` and `UNITY_EDITOR`.
These symbols can be used to switch compilation, for example:
```csharp
var a = 23;
#if UNITY_EDITOR
a = a * 3;
#else
a = a * 6;
#endif
```
ReSharper/Rider will only parse the branch of the `#if` statement that is active for the current context. It doesn't parse the inactive branch. This is for several reasons. For example, there is no guarantee that the inactive branch(es) are correct - people use preprocessor symbols as a means of commenting out.
But it's also because the amount of work required to parse for all combinations is unfeasible in an interactive application - one sample Unity project I have here has 66 symbols, the combination required to get full coverage here is huge.
And indeed, even if we did parse all combinations, running inspections and refactoring would now be greatly complicated - values can be initialised more than once, but not at all on another branch. There might be a chance of a null reference on one branch, but the variable might be unused on another. Understanding all of these combinations, merging the results and presenting useful information to the user is a significant problem.
So ReSharper/Rider will only run analysis, inspections, refactorings and so on, based on the current context. Switching context (such as changing from Debug to Release) will change the active pre-processor symbol set and re-run analysis. Essentially, ReSharper/Rider provide help for the current compile target only.
But this means that various refactorings and inspections can miss code in inactive branches (e.g. renaming a variable used in an inactive branch, find usages of a method that's also used in an inactive branch).
**This issue is NOT tracking a fix to this problem.**
This is a fundamental constraint on the way ReSharper can and does work, and is a non-trivial problem to solve. Instead this issue has two purposes - firstly to serve as an explanation why ReSharper/Rider behave like this. Secondly, to better understand how Unity uses preprocessor symbols, in case there is a more targeted approach ReSharper/Rider could take given a specific use case.
So the question is: how do Unity developers use preprocessor symbols? Are all of the 66 symbols in my test project used independently, or is there actually a more constrained set of contexts? Say, targeting multiple platforms (how many?) that each have a set of capabilities, which require, e.g. `ENABLE_AUDIO` on one, but not on another? Are there other uses of `#if`?
Contributor guide
Assessment
This issue has not been assessed yet.