Analyzing Indexers using Roslyn
I've occasionally come across code that just really bothers me. One such case that I have seen is the abuse of indexers. I have seen some programmers use this as a "free" method call that doesn't require a name. They load it up with parameters and it just doesn't feel right. For example, some code that looks like this:
public int this[string s, int i, long l]
{
get
{
// Do some weird stuff here
return s.GetHashCode();
}
}
This code is perfectly legal C#, but can be very confusing for someone coming into the code for the first time. Let's create an analyzer that raises a diagnostic any time there is more than one parameter to the indexer to mitigate the creation of this monstrosity. To start, we'll register a SyntaxNodeAction for
SyntaxKind.IndexerDeclaration` nodes.
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction((syntaxNodeContext) =>
{
}, SyntaxKind.IndexerDeclaration);
}
Next, we can get the node and check the ParameterList.Parameters
and check the Count
on that object.
var node = syntaxNodeContext.Node as IndexerDeclarationSyntax;
if (node == null)
return;
var paramCount = node.ParameterList.Parameters.Count();
Finally, we can raise a diagnostic if the parameter count is greater than 1. We'll also extract the class name from the indexer's parent, to provide a more meaningful diagnostic message.
if (paramCount > 1)
{
var className = (node.Parent as ClassDeclarationSyntax)?.Identifier.ToFullString().Trim();
syntaxNodeContext.ReportDiagnostic(Diagnostic.Create(Rule, node.ThisKeyword.GetLocation(), className));
}
So, the full diagnostic looks like this:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction((syntaxNodeContext) =>
{
var node = syntaxNodeContext.Node as IndexerDeclarationSyntax;
if (node == null)
return;
var paramCount = node.ParameterList.Parameters.Count();
if (paramCount > 1)
{
var className = (node.Parent as ClassDeclarationSyntax)?.Identifier.ToFullString().Trim();
syntaxNodeContext.ReportDiagnostic(Diagnostic.Create(Rule, node.ThisKeyword.GetLocation(), className));
}
}, SyntaxKind.IndexerDeclaration);
}
As you can see, once you know how to create an analyzer, you can easily create them to ensure the code you and your team are writing follow certain standards. You can also start creating a suite of standards that you like to follow to ensure you don't fall into any bad habits.