Improved Support for Source Generators in ReSharper 2021.2
The popularity of Source Generators is slowly yet steadily growing within the .NET community as more projects learn to utilize them to reduce tedious and repetitive development work. Newcomers can get an overview in our Source Generators introductory blog post, try various samples Microsoft provides, or watch the recorded talk “Source Generators in Practice” from JetBrains .NET Days Online.
Source generators are a fantastic tool that allows you to generate code at compile-time. For example, you can use generators to extend every type in your project with equality methods or automatically provide interfaces based on public API types. However, over time, working with generated code can become cumbersome. In addition, many ReSharper features aren’t available in source-generated files due to their unique status.
Generated files aren’t included directly in your solution since they are generated at compile time. ReSharper does allow viewing generated files in a temporary editor view. However, these temporary files cannot be modified, meaning you can’t edit the code or refactor it. Additionally, debugger tips aren’t available if you are stepping into source-generated code.
You may also notice that navigation features such as Find Usages and Go To Declaration are not always available. Even checking whether source-generated code contains compilation errors is difficult since these generated files aren’t part of the solution-wide analysis. Even opening the files in an editor won’t reveal any error highlighting, which may cause errors to go unnoticed until compilation occurs.
In ReSharper 2021.2, source-generated files get many of the same features human-written code files receive. We’ve added inlay hints, highlighting, navigation, and better syntax highlighting in source-generated files. The debugger now shows debugger tips to easily inspect what is happening in code. Generated code is also picked up by Solution-Wide Analysis (SWEA), so issues in generated code show up faster. Refactorings now also trigger source generators and verify that changes don’t result in a broken project. And finally, Find Usages lets you group generated sources.
Daemon, navigation, and debugger
As a ReSharper user, you will immediately notice one of the biggest problems working with source-generated code. There are no inspections, inlay hints don’t show you parameter names and types of variables, navigation features can’t be used on members in source-generated code. What a pain… well, not anymore!
Starting from ReSharper 2021.2, you’ll be able to cruise through source-generated code as if you wrote it yourself. All regular features such as inlay hints, error highlighting, navigation, semantical identifier coloring now support source-generated code.
Additionally, debugger tips are now available for source-generated code, helpful during debugging sessions. The moment you step into generated code, you’ll see tips that inform you about relevant variables’ current state and method call results.
Solution wide analysis
Solution Wide Analysis is now fully aware of source-generated files. The analysis will inspect any source-generated files along with developer-written ones. In addition, ReSharper’s analysis will immediately let you know if you’ve made changes that cause issues in source-generated code. For example, if you’ve removed a method used in a source-generated part of your solution.
In the following example, I accidentally created two backing fields that should create a property named
Title – one from the
_jobTitle field and one for the newly created
_title field. Solution wide analysis will immediately spot the problem in a generated file, letting me know about the problem and whether my changes fixed it.
Most developers hold source-generated code to a different standard than hand-written code. For example, code redundancy and stylistic preferences are less important in generated code, as we value the function of the code over the form it takes. In short, we just want it to work. ReSharper will recognize source-generated files and thus avoid nagging us about most stylistic choices and code redundancies that differ from our own preferences.
Source generators are meant to reduce the code we write, but this might mean a generator will have a larger impact across our codebase. For example, a change to one hand-written code file could cause a source generator to cascade changes to dozens of files on every keystroke. The dramatic changes in our codebase will mean our solution needs to be reanalyzed to detect potential breaking changes.
In addition, extreme file changes may indicate a problem in the generator itself. If you ever come across this issue or find analyzing generated files unnecessary for your use case, you have an option to disable solution wide analysis for all source generated files with a new setting in the ReSharper options: Code Inspection | Settings | Enable solution-wide analysis | Include source generated files.
Global refactorings can now be triggered from source-generated files. However, you may have noticed that source-generated code is read-only and cannot be permanently edited. Nevertheless, a simple change in the solution will trigger a source generator, undoing any changes to generated code. So why would we ever need refactorings in source-generated code?
Let’s look at two scenarios where refactorings make sense.
Refactoring Generated And Hand-Written Code At Once
First, source-generated elements are often based on entities in your hand-written code. The
[AutoNotify] generator example provided by Microsoft helps native developers avoid boilerplate code by triggering
INotifyPropertyChanged events. Using ReSharper in the source-generated file, we can update both the backing field and the generated property with one refactoring. The generated property will be re-created with the correct name based on the resulting name of the backing field. It’s almost magical, especially if you know all the underlying intricacies!
Safely Changing Input For Source Generators
Surprisingly, it may be beneficial to use refactorings for code generated from non-code files like CSV files, JSON, or other static assets. For example, we have a source generator attribute that takes a path to a static CSV file as input. Changing the parameter would alter the context of the previously generated code, immediately invalidating your codebase. Furthermore, such a change might introduce hundreds of compilation errors that would have to be fixed manually.
Instead, you can use a Change signature refactoring to the source generated method first. Using the refactoring will correctly apply changes to every call site throughout the entire solution and then proceed with the generator’s input change. This way, even though the generated code cannot be changed, we can rely on the refactoring to update usages of this code and sort out every possible problem, such as ensuring a correct overload is chosen before we update what is generated.
One final thing we’ve tackled in this update is improved integration of search results from source-generated files in the Find usages window. The tool window can group results into many grouping modes to help you easily find matches within your solution, the default and most common grouping being Project structure. Project structure group results are organized by the location of files, folders, and projects.
Source-generated files presented an interesting challenge to this grouping since they aren’t directly included in your solution at all; hence they don’t have a correct position in the project structure.
In 2021.2, we’ve introduced a virtual project model structure for source-generated files. Source-generated files are now grouped in a per-project virtual folder called Source generated files to immediately let you know which results are from your own code and which ones are generated. The default mode also groups source-generated files within the folder by the specific generator that produced the file. This might be useful if you have multiple generators extending the same type and are generating files with similar or even equivalent names.
Source generators will undoubtedly change the way many .NET developers build future applications. Generating code can reduce tedious tasks, which can help reduce common copy and paste errors. While it may all feel like magic, we like to think of it more as an advanced science; a powerful tool that we should all be capable of understanding.
Using tools like ReSharper allows you to understand and interact with all parts of your applications, whether hand-written, generated, or a combination of the two approaches. With the new source generator-focused features in ReSharper 2021.2, developers will have unrivaled access to generated code and have greater solution-wide insights into their codebases. We hope you learned a few new things from this post and hope you find them helpful as you learn more about source generators.
To try out these new features, please download ReSharper 2021.2. As always, all feedback and comments are appreciated.