Book Image

Roslyn Cookbook

Book Image

Roslyn Cookbook

Overview of this book

Open-sourcing the C# and Visual Basic compilers is one of the most appreciated things by the .NET community, especially as it exposes rich code analysis APIs to analyze and edit code. If you want to use Roslyn API to write powerful extensions and contribute to the C# developer tool chain, then this book is for you. Additionally, if you are just a .NET developer and want to use this rich Roslyn-based functionality in Visual Studio to improve the code quality and maintenance of your code base, then this book is also for you. This book is divided into the following broad modules: 1. Writing and consuming analyzers/fixers (Chapters 1 - 5): You will learn to write different categories of Roslyn analyzers and harness and configure analyzers in your C# projects to catch quality, security and performance issues. Moving ahead, you will learn how to improve code maintenance and readability by using code fixes and refactorings and also learn how to write them. 2. Using Roslyn-based agile development features (Chapters 6 and 7): You will learn how to improve developer productivity in Visual Studio by using features such as live unit testing, C# interactive and scripting. 3. Contributing to the C# language and compiler tool chain (Chapters 8 - 10): You will see the power of open-sourcing the Roslyn compiler via the simple steps this book provides; thus, you will contribute a completely new C# language feature and implement it in the Roslyn compiler codebase. Finally, you will write simple command line tools based on the Roslyn service API to analyze and edit C# code.
Table of Contents (19 chapters)
Title Page
Credits
About the Author
Acknowledgments
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface
Dedication

Creating, debugging, and executing an analyzer project in Visual Studio


We will show you how to install the .NET Compiler Platform SDK, create an analyzer project from a template, and then debug and execute the default analyzer.

Note

The analyzer project that you create in this recipe can be used in the subsequent recipes in this chapter to add new analyzers and write unit tests.

Getting ready

You will need to have Visual Studio 2017 installed on your machine to execute the recipes in this chapter. You can install a free community version of Visual Studio 2017 from https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15.

How to do it...

  1. Start Visual Studio and click on File | New | Project.
  2. Search for Analyzer templates in the textbox at the top right corner of the New Project dialog, select Download the .NET Compiler Platform SDK, and click on OK:
  1. The new project will have an index.html file opened by default. Click on Download .NET Compiler Platform SDK Templates >> button to install the analyzer SDK templates.
  1. In the subsequent File Download dialog, click on Open.
  1. Click Install on the next VSIX Installer dialog and End Tasks on the subsequent prompt to install the SDK:
  1. Start a new instance of Visual Studio and click on File | New | Project... to get the New Project dialog.
  2. Change the project target framework combo box to .NET Framework 4.6 (or above). Under Visual C# | Extensibility, choose Analyzer with Code Fix (NuGet + VSIX), name your project CSharpAnalyzers, and click on OK.

  1. You should now have an analyzers solution with 3 projects: CSharpAnalyzers (Portable), CSharpAnalyzers.Test , and CSharpAnalyzer.Vsix:
  1. Open source file DiagnosticAnalyzer.cs in CSharpAnalyzers project and set breakpoints (press F9) at the start of the Initialize and AnalyzeSymbol methods, as shown here:
  1. Set CSharpAnalyzers.Vsix as the start-up project and click on F5 to build the analyzer and start debugging a new instance of Visual Studio with the analyzer enabled.
  2. In the new Visual Studio instance, create a new C# class library project, say ClassLibrary.
  3. Verify that we hit both the preceding breakpoints in our analyzer code in the first VS instance. You can step through the analyzer code using F10 or click on F5 to continue debugging.

 

  1. We should now see the analyzer diagnostic in the error list and a squiggle in the editor:
  1. Edit the name of the class from Class1 to CLASS1.
  2. We should hit the breakpoint in the AnalyzeSymbol method again. Continue debugging with F5 and the diagnostic and squiggle should go away immediately, demonstrating the powerful live and extensible analysis.

How it works...

.NET Compiler Platform SDK is a wrapper project that redirects us to fetch the project templates for analyzer + CodeFix projects for C# and Visual Basic. Creating a new project from these templates creates a fully functional analyzer project which has a default analyzer, unit tests, and a VSIX project:

  • CSharpAnalyzers: Core analyzer project that contains the default analyzer implementation that reports a diagnostic for all type names that contain any lowercase letters.
  • CSharpAnalyzers.Test: Analyzer unit test project that contains a couple of analyzer and code fixer unit tests and test helpers.
  • CSharpAnalyzers.Vsix: The VSIX project that packages the analyzer into a VSIX. This is the start-up project in the solution.

Clicking on F5 to start debugging the solution builds and deploys the analyzer to the Visual Studio extension hive and then starts a new Visual Studio instance from this hive. Our analyzer is enabled by default for all C# projects created in this VS instance.

Let's expand a bit more on the diagnostic analyzer source code defined in DiagnosticAnalyzers.cs. It contains a type named CSharpAnalyzersAnalyzer, which derives from DiagnosticAnalyzer. DiagnosticAnalyzer is an abstract type with the following two abstract members:

  • SupportedDiagnostics property: Analyzer must define one or more supported diagnostic descriptors. Descriptors describe the metadata for the diagnostics that an analyzer can report in analyzer actions. It contains fields such as the diagnostic ID, message format, title, description, hyperlink to documentation for the diagnostic, and so on. Can be used to create and report diagnostics:
private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
  • Initialize method: Diagnostic analyzers must implement the Initialize method to register analyzer action callbacks for a specific code entity kind of interest, which is named type symbols for the default analyzer. The initialize method is invoked once for the analyzer lifetime to allow analyzer initialization and registration of actions.
 public override void Initialize(AnalysisContext context)
 {
  context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
 }

 private static void AnalyzeSymbol(SymbolAnalysisContext context)
 {
   ...
 }

Note

Invoke AnalysisContext.EnableConcurrentExecution() in the Initialize method if your analyzer can handle action callbacks from multiple threads simultaneously -- this enables the analyzer driver to execute the analyzer more efficiently on a machine with multiple cores. Additionally, also invoke AnalysisContext.ConfigureGeneratedCodeAnalysis() in theInitialize method to configure whether or not the analyzer wants to analyze and/or report diagnostics in generated code.

Analyzer actions are invoked for every code entity of interest in a user s source code. Additionally, as the user edits code and a new compilation is created, action callbacks are continuously invoked for entities defined in the new compilation during code editing. The error list makes sure that it only reports the diagnostics from the active compilation.

Note

Use http://source.roslyn.io for rich semantic search and navigation of Roslyn source code, which is open sourced at https://github.com/dotnet/roslyn.git. For example, you can look at the definition and references for DiagnosticAnalyzer using the query URL http://source.roslyn.io/#q=DiagnosticAnalyzer.