Working with If Blocks in Your Code Analyzers
Once you start writing your analyzers, you will eventually run into a scenario where you have to handle an if
block. If
blocks like any other blocks of code have a few nuances that you need to understand when working with them.
To start analyzing if
blocks, you can register a SyntaxNodeAction
for the SyntaxKind.IfStatement
:
context.RegisterSyntaxNodeAction((syntaxNodeContext)=>
{
}, SyntaxKind.IfStatement);
Now before we start analyzing the IfStatementSyntax
, we should first look at the components of the syntax. Take for example the following code:
Breaking down this statement, each of the different colors maps to different properties on the IfStatementSyntax
as demonstrated in the chart below.
Statement | Explanation |
---|---|
if |
This is represented by the IfKeyword property on the IfStatementSyntax
|
(x==null) |
This is represented by the Condition property on the IfStatementSyntax
|
{ // Do stuff } |
This is represented by the Statement property on the IfStatementSyntax
|
else { // Do other stuff } |
This is represented by the Else property on the IfStatementSyntax
|
Now that you have a basic understanding of the different elements in the IfStatementSyntax
, you can take the node passed into the method via the syntaxNodeContext
to access the If
statement. So, if for example we wanted to raise a diagnostic anytime someone checked != null
, we could start by looking at the condition as a BinaryExpressionSyntax
var node = syntaxNodeContext.Node as IfStatementSyntax;
var binaryExpression = node.Condition as BinaryExpressionSyntax;
if (binaryExpression == null)
return;
Next, the binaryExpression
has a kind that we can check to make sure it is a NotEqualsException
.
if (binaryExpression.IsKind(SyntaxKind.NotEqualsExpression))
{
}
The binary expression contains a left and right portion of the expression. Since we are looking to see if one side of the expression is null, we can simply cast the left and right portions of the expression to a LiteralExpressionSyntax
and check to see if that is a NullLiteralExpression
. If either side matches that criteria, then we can raise the diagnostic.
var left = binaryExpression.Left as LiteralExpressionSyntax;
var right = binaryExpression.Right as LiteralExpressionSyntax;
if (left != null && left.IsKind(SyntaxKind.NullLiteralExpression)
||(right !=null && right.IsKind(SyntaxKind.NullLiteralExpression)))
{
syntaxNodeContext.ReportDiagnostic(Diagnostic.Create(Rule, binaryExpression.GetLocation()));
}
So in the end, our full diagnostic looks like this:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction((syntaxNodeContext)=>
{
var node = syntaxNodeContext.Node as IfStatementSyntax;
var binaryExpression = node.Condition as BinaryExpressionSyntax;
if (binaryExpression == null)
return;
if (binaryExpression.IsKind(SyntaxKind.NotEqualsExpression))
{
var left = binaryExpression.Left as LiteralExpressionSyntax;
var right = binaryExpression.Right as LiteralExpressionSyntax;
if (left != null && left.IsKind(SyntaxKind.NullLiteralExpression)
||(right !=null && right.IsKind(SyntaxKind.NullLiteralExpression)))
{
syntaxNodeContext.ReportDiagnostic(Diagnostic.Create(Rule, binaryExpression.GetLocation()));
}
}
}, SyntaxKind.IfStatement);
}
As I demonstrated, the processing of if
statements in your analyzers is not difficult and can be a very powerful construct to use in your analyzer. There is obviously much more that can be done with the processing of if
statements and I would encourage you to take the time and learn more about them.