C# Corner

Roslyn Update: The State of the .NET Compiler Platform

Now that Visual Studio 2015 is upon us, here's a brief overview of the capabilities of the .NET Compiler Platform.

"Project Roslyn," formally known as the Microsoft .NET Compiler Platform, has been in incubation since 2008. Well, it's ready for inception in Visual Studio 2015.

Roslyn is a compiler API for both C# and Visual Basic. What this means is that you have full access to the internal compilation structure of your code now. This allows for many interesting use cases such as static code analysis, code generation and read-eval-print-loop (REPL) functionality for C# and Visual Basic.

In this article, I'll cover how to use the C# Roslyn API to create a code diagnostic, as well as a quick-fix that can uppercase constant field members.

To get started, install the .NET Compiler Platform SDK Templates for Visual Studio 2015 RC from the Visual Studio Gallery. You can also install the .NET Compiler Platform SDK from the Visual Studio Extensions and Updates window (see Figure 1).

[Click on image for larger view.] Figure 1. .NET Compiler Platform SDK Installation

Next, install the Visual Studio 2015 RC SDK from the download page.

Then, create a new Analyzer with Code Fix project as seen in Figure 2.

[Click on image for larger view.] Figure 2. New Analyzer with Code Fix Project

First, open up the Resources.resx resource file and update the values for each key (Figure 3) to reflect that the fix is for constant field names.

[Click on image for larger view.] Figure 3. Updated Resources.resx Resource File

Then open up the DiagnosticAnalyzer.cs code file. The DiagnosticAnalayzer class is responsible for generating the code fix warning for Visual Studio. Next, update the Initialize method to analyze only field symbols:

public override void Initialize(AnalysisContext context)
{
  context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Field);
}

Next, update the AnalyzeSymbol method to create a diagnostic for only field symbols that contain lowercase letters and have a constant value:

private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
  var fieldSymbol = (IFieldSymbol)context.Symbol;
  if (fieldSymbol.Name.ToCharArray().Any(char.IsLower) && fieldSymbol.ConstantValue != null)
  {
    var diagnostic = Diagnostic.Create(Rule, fieldSymbol.Locations[0], fieldSymbol.Name);
    context.ReportDiagnostic(diagnostic);
  }
}

Now it's time to update the CodeFixProvider class to allow the fix to be previewed and fixed. First, update the RegisterCodeFixesAsync method to find the field declarations that need to be fixed, as shown in Listing 1.

Listing 1: Updating the RegisterCodeFixesAsync Method
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
  var root = await context.Document.GetSyntaxRootAsync(
    context.CancellationToken).ConfigureAwait(false);
  var diagnostic = context.Diagnostics.First();
  var diagnosticSpan = diagnostic.Location.SourceSpan;
  var declaration = root.FindToken(
    diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<FieldDeclarationSyntax>().First();
  context.RegisterCodeFix(
    CodeAction.Create("Make uppercase", c => 
    MakeUppercaseAsync(context.Document, declaration, c)),
    diagnostic);
}

Then update the MakeUppercaseAsync method to fix the given field declaration syntax by making the type name be uppercase. First, get the semantic model:

var semanticModel = await document.GetSemanticModelAsync(cancellationToken);

Then get the field symbol for the field declaration from the semantic model:

IFieldSymbol fieldSybmol = null;
fieldSybmol = 
  semanticModel.GetDeclaredSymbol(
  fieldDecl.Declaration.Variables.First()) as IFieldSymbol;

Then generate the uppercased field symbol name:

string newName = fieldSybmol.Name.ToUpperInvariant();
Next, get the original solution and workspace options:
var originalSolution = document.Project.Solution;
var optionSet = originalSolution.Workspace.Options;
Last, create and return a new solution with the field symbol renamed:
var newSolution = await Renamer.RenameSymbolAsync(
  document.Project.Solution, fieldSybmol, newName, optionSet, 
  cancellationToken).ConfigureAwait(false);
return newSolution;

Now you should be able to run the solution and test out the fix by creating a constant private field as seen in Figure 4.

[Click on image for larger view.] Figure 4. Code Fix in Action

Next you can click on the light bulb and preview the fix (Figure 5).

[Click on image for larger view.] Figure 5. Code Fix Preview in Action

Finally, you can apply the code fix and see it applied by clicking on the Make uppercase option as seen in Figure 6.

[Click on image for larger view.] Figure 6. Make Uppercase Option

I've covered creating a new diagnostic analyzer and code fix. You can analyze one or many symbol or syntax types using Rosyln. After the code fix is created you can deploy it either as a NuGet package or as a .vsix installer.

As you can see, Roslyn opens up Visual Studio to be extended with custom static code analysis and refactoring plug-ins.

About the Author

Eric Vogel is a Senior Software Developer for Red Cedar Solutions Group in Okemos, Michigan. He is the president of the Greater Lansing User Group for .NET. Eric enjoys learning about software architecture and craftsmanship, and is always looking for ways to create more robust and testable applications. Contact him at [email protected].

comments powered by Disqus

Featured

Subscribe on YouTube