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); }
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.
- In
Solution Explorer
, double-click on theResources.resx
file inCSharpAnalyzers
project to open the resource file in the resource editor. - Replace the existing resource strings for
AnalyzerDescription
,AnalyzerMessageFormat
andAnalyzerTitle
with new strings.
- 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); } } }); }
- Click on Ctrl + F5 to start a new Visual Studio instance with the analyzer enabled.
- 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); } } }
- Verify the analyzer diagnostic is neither reported for the method block for
Method
nor thewhile
statement, but is reported for theif
statement andSystem.Console.WriteLine
invocation statement:
- Now, add curly braces around the
System.Console.WriteLine
invocation statement and verify the only single warning is now reported for theif
statement:
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); }