I'm writing a custom analyzer rule using Roslyn.
I want to find a method which is a handler for some event (via subscription). Like this:
public class Counter
{
public event EventHandler ThresholdReached;
}
public class TestEvent
{
public TestEvent()
{
Counter с = new Counter();
с.ThresholdReached += OnThresholdReached;
}
private void OnThresholdReached(object sender, EventArgs e)
{
}
}
In my realization it looks:
private static void HandleMethodDeclaration(SyntaxNodeAnalysisContext context)
{
MethodDeclarationSyntax methodDeclaration = (MethodDeclarationSyntax)context.Node;
if (methodDeclaration.Identifier.IsMissing)
{
return;
}
IMethodSymbol methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration);
}
I don't know how to detect that OnThresholdReached is subscription of Event ThresholdReached. If someone knows how to do it, please help=)
In an analyzer, you cannot know only from looking at a MethodDeclarationSyntax
, whether that method is converted to a delegate or not. Because of that, you can not know (only from looking at a MethodDeclarationSyntax
) whether that delegate is passed to the add accessor of an event or not.
First of all, remember that a Roslyn analyzer can only see usages in the current assembly (project). If your method is converted to a delegate in another assembly, there is no way for the analyzer to see this.
Secondly, remember that
с.ThresholdReached += OnThresholdReached;
may be expressed as
EventHandler handler = OnThresholdReached;
с.ThresholdReached += handler;
If you only want to detect the first case, you can look at AssignmentExpressionSyntax
instances of kind SyntaxKind.AddAssignmentExpression
, and analyze those.
If you want to detect all cases where a method group is converted to a delegate, you need to look at all instances of type SimpleNameSyntax
and analyze those as follows:
void Analyze(SyntaxNodeAnalysisContext context)
{
var node = context.Node as SimpleNameSyntax;
// we're only interested in delegates
var type = context.SemanticModel.GetTypeInfo(node, context.CancellationToken).ConvertedType;
if (type == null || type.TypeKind != TypeKind.Delegate)
{
return;
}
// we're only interested in methods from the current assembly
var symbol = context.SemanticModel.GetSymbolInfo(node, context.CancellationToken).Symbol;
if (symbol == null ||
symbol.Kind != SymbolKind.Method ||
!symbol.ContainingAssembly.Equals(context.SemanticModel.Compilation.Assembly))
{
return;
}
// now you know symbol is a method in the same assembly, that is converted to a delegate
}
To find the source code for that method, see https://stackoverflow.com/a/45362532/1403794.