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 a syntax tree analyzer to analyze the source file and report syntax issues


A syntax tree analyzer registers action callbacks to analyze the syntax/grammar for the source file and reports pure syntactic issues. For example, a missing semicolon at the end of a statement is a syntactic error, while assigning an incompatible type to a symbol with no possible type conversion is a semantic error.

In this section, we will write a syntax tree analyzer that analyzes all the statements in a source file and generates a syntax warning for any statement that is not enclosed in a block, that is curly braces { and }. For example, the following code will generate a warning for both the if statement and the System.Console.WriteLine invocation statement, but the while statement is not flagged:

void Method()
{
 while (...)
  if (...)
   System.Console.WriteLine(value);
}

Getting ready

You will need to have created and opened an analyzer project, say CSharpAnalyzers in Visual Studio 2017. Refer to the first recipe in this chapter to create this project.

How to do it...

  1. In Solution Explorer, double-click on the Resources.resx file in CSharpAnalyzers project to open the resource file in the resource editor.
  2. Replace the existing resource strings for AnalyzerDescription, AnalyzerMessageFormat and AnalyzerTitle with new strings.
  1. Replace the Initialize method implementation with the following:
public override void Initialize(AnalysisContext context)
{
   context.RegisterSyntaxTreeAction(syntaxTreeContext =>
   {
     // Iterate through all statements in the tree.
     var root = syntaxTreeContext.Tree.GetRoot(syntaxTreeContext.CancellationToken);
     foreach (var statement in root.DescendantNodes().OfType<StatementSyntax>())
     {
       // Skip analyzing block statements.
       if (statement is BlockSyntax)
       {
         continue;
       }

       // Report issue for all statements that are nested within a statement,
       // but not a block statement.
       if (statement.Parent is StatementSyntax && !(statement.Parent is BlockSyntax))
       {
         var diagnostic = Diagnostic.Create(Rule, statement.GetFirstToken().GetLocation());
         syntaxTreeContext.ReportDiagnostic(diagnostic);
       }
     }
   });
}
  1. Click on Ctrl + F5 to start a new Visual Studio instance with the analyzer enabled.
  2. In the new Visual Studio instance, create a new C# class library with the following code:
namespace ClassLibrary
{
  public class Class1
  {
    void Method(bool flag, int value)
    {
      while (flag)
      if (value > 0)
      System.Console.WriteLine(value);
    }
  }
}
  1. Verify the analyzer diagnostic is neither reported for the method block for Method nor the while statement, but is reported for the if statement and System.Console.WriteLine invocation statement:
  1. Now, add curly braces around the System.Console.WriteLine invocation statement and verify the only single warning is now reported for the if statement:

How it works...

Syntax tree analyzers register callbacks to analyze syntax of all source files in the compilation. Our analysis works by getting the roots of the syntax tree and then operating on all the descendant syntax nodes of the roots which are of type StatementSyntax. First, we note that a block statement is itself an aggregate statement, and by definition has curly braces, so we skip past these.

// Skip analyzing block statements.
if (statement is BlockSyntax)
{
  continue;
}

We then perform syntactic checks for the parent of statement syntax. If the parent of the statement is also a statement, but not a block with curly braces, then we report a diagnostic on the first syntax token of the statement recommending usage of curly braces.

// Report issue for all statements that are nested within a statement,
// but not a block statement.
if (statement.Parent is StatementSyntax && !(statement.Parent is BlockSyntax))
{
  var diagnostic = Diagnostic.Create(Rule, statement.GetFirstToken().GetLocation());
  syntaxTreeContext.ReportDiagnostic(diagnostic);
}

Note

SyntaxTreeAnalysisContext provided to syntax tree actions does not expose the semantic model for the source file, hence no semantic analysis can be performed within a syntax tree action.