Learn Roslyn Now: Part 11 Introduction to Code Fixes

Last time (three months ago, jeez) we talked about building our first analyzer and what we get out of the box with the default analyzer template. Today we’ll talk about the second half of the analyzer project: The Code Fix Provider.


The first thing to notice is that our class inherits from CodeFixProvider. If you take a quick look at CodeFixProvider, you’ll see that it expects you to provide at least two things:

FixableDiagnosticsIds – A list of diagnostic IDs that we would like our code fix to deal with. We would have defined these IDs in our original analyzer.

RegisterCodeFixesAsync – Registers our code fix within Visual Studio to handle our diagnostic(s).

GetFixAllProvider – An optional FixAllProvider that can apply your code fix to all the occurrences of a diagnostic.

Let’s take a look at the first half of this file:

First, we can see that we’re exporting a code fix provider for C# with the name “Analyzer1CodeFixProvider”. We can also specify additional languages such as VB if you’re writing a multi-language code fix. Note that we have to specify the name explicitly here. (Name is a property in ExportCodeFixProvider. I’d actually never come across this attribute-specific syntax before.)

To start, we’ve got the title of the analyzer which is self explanatory. We’ll expose this title to Visual Studio when we register our code fix action.

Next, we’ve got to expose a list of diagnostics for which we’d like to provide our code fix. In this case, we expose the analyzer we created in the introduction to analyzers.

Finally, the default codefix template overrides the optional GetFixAllProvider. In this case they provide a BatchFixerThe BatchFixer computes all the required changes in parallel and then applies them to the solution at one time.

Now we’ll take a look at the last two methods given to us in CodeFixProvider.cs

The first is RegisterCodeFixesAsync and it accepts a CodeFixContext. The CodeFixContext has information about where we can apply our code fix, and what diagnostics are available for us to register our code fix against. CodFixContext provides a list of diagnostics for us to choose from based on what we exposed in FixableDiagnosticIds.

Based on my experiments, RegisterCodeFixesAsync is run every time the Visual Studio light bulb appears due to a diagnostic we’ve declared interest in. At this point we can register a action to run that we’d like to apply if the user selects our code fix. We do this with context.RegisterCodeFix(). We pass in a title, a function that returns a solution with our change and an optional equivalence key. The title is simply what will be displayed to the user when they see our fix as an option. In the default template it’s “Make uppercase” which you can see below:


Clicking on the code fix runs MakeUppercaseAsync. There’s admittedly a lot of overhead here for what seems like a trivial change. The real work occurs in Renamer.RenameSymbolAsync() an API that quickly and easily renames symbols for us across an entire solution. Remember that Roslyn objects are immutable, so we are given an entirely new solution (newSolution) which we return from our method. Now Visual Studio will replace the previous solution with our updated copy.

One final note to make is regarding equivalenceKey. The equivalence key is used to match our code fix against other code fixes and see whether or not they’re the same. To my knowledge, there’s no commonly agreed upon format for these keys. However it looks like projects such as StyleCopAnalyzers are using a similar approach to Microsoft and name theirs with a two letter code followed by a number (eg. SA1510CodeFixProvider).
And there you have it. That’s the base case analyzer that ships with Visual Studio. Obviously we can build much more powerful analyzers and code fixes, but this project should serve as a nice starting point for most people. For more advanced analyzers check out StyleCopAnalyzers, Code Cracker or the Roslyn Analyzers.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s