11using System ;
22using System . Collections . Immutable ;
3+ using System . Reflection ;
34using CSharpGuidelinesAnalyzer . Extensions ;
45using JetBrains . Annotations ;
56using Microsoft . CodeAnalysis ;
@@ -41,7 +42,7 @@ public override void Initialize([NotNull] AnalysisContext context)
4142
4243 private static void AnalyzeEventAssignment ( OperationAnalysisContext context )
4344 {
44- var assignment = ( IEventAssignmentOperation ) context . Operation ;
45+ var assignment = new PortableEventAssignmentOperation ( ( IEventAssignmentOperation ) context . Operation ) ;
4546
4647 if ( ! assignment . Adds )
4748 {
@@ -58,16 +59,19 @@ private static void AnalyzeEventAssignment(OperationAnalysisContext context)
5859 }
5960
6061 private static void AnalyzeEventAssignmentMethod ( [ NotNull ] IMethodReferenceOperation binding ,
61- [ NotNull ] IEventAssignmentOperation assignment , OperationAnalysisContext context )
62+ [ NotNull ] PortableEventAssignmentOperation assignment , OperationAnalysisContext context )
6263 {
63- string eventTargetName = GetEventTargetName ( assignment . EventReference , binding . Method ) ;
64- string handlerNameExpected = string . Concat ( eventTargetName , "On" , assignment . EventReference . Event . Name ) ;
65-
66- string handlerNameActual = binding . Method . Name ;
67- if ( handlerNameActual != handlerNameExpected )
64+ if ( assignment . EventReference != null )
6865 {
69- context . ReportDiagnostic ( Diagnostic . Create ( Rule , binding . Syntax . GetLocation ( ) , binding . Method . GetKind ( ) ,
70- handlerNameActual , assignment . EventReference . Event . Name , handlerNameExpected ) ) ;
66+ string eventTargetName = GetEventTargetName ( assignment . EventReference , binding . Method ) ;
67+ string handlerNameExpected = string . Concat ( eventTargetName , "On" , assignment . EventReference . Event . Name ) ;
68+
69+ string handlerNameActual = binding . Method . Name ;
70+ if ( handlerNameActual != handlerNameExpected )
71+ {
72+ context . ReportDiagnostic ( Diagnostic . Create ( Rule , binding . Syntax . GetLocation ( ) , binding . Method . GetKind ( ) ,
73+ handlerNameActual , assignment . EventReference . Event . Name , handlerNameExpected ) ) ;
74+ }
7175 }
7276 }
7377
@@ -126,5 +130,40 @@ private static string GetStaticEventTargetName([NotNull] IEventReferenceOperatio
126130 bool isEventLocal = eventContainingType . Equals ( targetMethod . ContainingType ) ;
127131 return isEventLocal ? string . Empty : eventContainingType . Name ;
128132 }
133+
134+ private sealed class PortableEventAssignmentOperation
135+ {
136+ [ NotNull ]
137+ private readonly IEventAssignmentOperation operation ;
138+
139+ public PortableEventAssignmentOperation ( [ NotNull ] IEventAssignmentOperation operation )
140+ {
141+ Guard . NotNull ( operation , nameof ( operation ) ) ;
142+
143+ this . operation = operation ;
144+ EventReference = TryGetEventReference ( operation ) ;
145+ }
146+
147+ [ CanBeNull ]
148+ public IEventReferenceOperation EventReference { get ; }
149+
150+ [ NotNull ]
151+ public IOperation HandlerValue => operation . HandlerValue ;
152+
153+ public bool Adds => operation . Adds ;
154+
155+ [ CanBeNull ]
156+ private static IEventReferenceOperation TryGetEventReference ( [ NotNull ] IEventAssignmentOperation operation )
157+ {
158+ // Breaking change in Microoft.CodeAnalysis v2.9:
159+ // type of IEventAssignmentOperation.EventReference was changed from IEventReferenceOperation to IOperation.
160+ PropertyInfo propertyInfo = typeof ( IEventAssignmentOperation ) . GetRuntimeProperty ( "EventReference" ) ;
161+ object propertyValue = propertyInfo . GetMethod . Invoke ( operation , Array . Empty < object > ( ) ) ;
162+
163+ return typeof ( IEventReferenceOperation ) . GetTypeInfo ( ) . IsAssignableFrom ( propertyValue . GetType ( ) . GetTypeInfo ( ) )
164+ ? ( IEventReferenceOperation ) propertyValue
165+ : null ;
166+ }
167+ }
129168 }
130169}
0 commit comments