From 5aca5d788ce74736bdc3f13520057ea53bc2f986 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 18 Jul 2017 12:48:56 -0700 Subject: [PATCH 01/11] Fix IEventAssignmentExpression --- .../Operations/CSharpOperationFactory.cs | 20 +- ...erationTests_IEventAssignmentExpression.cs | 207 ++++++++++++++++++ .../Generated/Operations.xml.Generated.cs | 29 +-- .../Operations/IEventAssignmentExpression.cs | 13 +- .../Operations/IEventReferenceExpression.cs | 2 - .../Core/Portable/PublicAPI.Unshipped.txt | 3 +- .../VisualBasicOperationFactory_Methods.vb | 12 +- ...erationTests_IEventAssignmentExpression.vb | 173 +++++++++++++++ .../Compilation/OperationTreeVerifier.cs | 3 +- .../Compilation/TestOperationWalker.cs | 1 - .../Diagnostics/OperationTestAnalyzer.cs | 11 +- 11 files changed, 420 insertions(+), 54 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs create mode 100644 src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 3644c9f890ea7..988a88ea6e8dd 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -355,14 +355,26 @@ private IEventReferenceExpression CreateBoundEventAccessOperation(BoundEventAcce private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(BoundEventAssignmentOperator boundEventAssignmentOperator) { - IEventSymbol @event = boundEventAssignmentOperator.Event; - Lazy eventInstance = new Lazy(() => Create(boundEventAssignmentOperator.Event.IsStatic ? null : boundEventAssignmentOperator.ReceiverOpt)); + SyntaxNode syntax = boundEventAssignmentOperator.Syntax; + Lazy eventReference = new Lazy(() => + { + IEventSymbol @event = boundEventAssignmentOperator.Event; + Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.Event.IsStatic ? null : boundEventAssignmentOperator.ReceiverOpt)); + ISymbol member = boundEventAssignmentOperator.Event; + // BoundEventAssignmentOperator doesn't hold on to all the data from the provided BoundEventAccess during binding. + // Based on the implementation of those two bound node types, the following data can be retieved w/o changing BoundEventAssignmentOperator: + // 1. The type of BoundEventAccess is the type of the event symbol. + // 2. the constant value of BoundEventAccess is always null. + // However, we can't reliably get the syntax node for the BoundEventAccess w/o changing BoundEventAssignmentOperator, so the syntax of entire + // BoundEventAssignmentOperator is used instead. + return new LazyEventReferenceExpression(@event, instance, @event, syntax, @event.Type, ConvertToOptional(null)); + }); + Lazy handlerValue = new Lazy(() => Create(boundEventAssignmentOperator.Argument)); bool adds = boundEventAssignmentOperator.IsAddition; - SyntaxNode syntax = boundEventAssignmentOperator.Syntax; ITypeSymbol type = boundEventAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundEventAssignmentOperator.ConstantValue); - return new LazyEventAssignmentExpression(@event, eventInstance, handlerValue, adds, syntax, type, constantValue); + return new LazyEventAssignmentExpression(eventReference, handlerValue, adds, syntax, type, constantValue); } private IParameterReferenceExpression CreateBoundParameterOperation(BoundParameter boundParameter) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs new file mode 100644 index 0000000000000..09991493348d2 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs @@ -0,0 +1,207 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public partial class IOperationTests : SemanticModelTestBase + { + [Fact] + public void AddEventHandler() + { + string source = @" +using System; + +class Test +{ + public event EventHandler MyEvent; +} + +class C +{ + void Handler(object sender, EventArgs e) + { + } + + void M() + { + var t = new Test(); + /**/t.MyEvent += Handler/**/; + } +} +"; + string expectedOperationTree = @" +IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 't.MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 't.MyEvent += Handler') + Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test) (Syntax: 't') + Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler') +"; + var expectedDiagnostics = new[] { + // file.cs(6,31): warning CS0067: The event 'Test.MyEvent' is never used + // public event EventHandler MyEvent; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "MyEvent").WithArguments("Test.MyEvent").WithLocation(6, 31) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [Fact] + public void RemoveEventHandler() + { + string source = @" +using System; + +class Test +{ + public event EventHandler MyEvent; +} + +class C +{ + void M() + { + var t = new Test(); + /**/t.MyEvent -= null/**/; + } +} +"; + string expectedOperationTree = @" +IEventAssignmentExpression (EventRemove)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 't.MyEvent -= null') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 't.MyEvent -= null') + Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test) (Syntax: 't') + Handler: IConversionExpression (ConversionKind.Cast, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler, Constant: null) (Syntax: 'null') + ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: null, Constant: null) (Syntax: 'null') +"; + var expectedDiagnostics = new[] { + // file.cs(6,31): warning CS0067: The event 'Test.MyEvent' is never used + // public event EventHandler MyEvent; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "MyEvent").WithArguments("Test.MyEvent").WithLocation(6, 31) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [Fact] + public void AddEventHandler_StaticEvent() + { + string source = @" +using System; + +class Test +{ + public static event EventHandler MyEvent; +} + +class C +{ + void Handler(object sender, EventArgs e) + { + } + + void M() + { + /**/Test.MyEvent += Handler/**/; + } +} +"; + string expectedOperationTree = @" +IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 'Test.MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (Static) (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 'Test.MyEvent += Handler') + Instance Receiver: null + Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler') +"; + var expectedDiagnostics = new[] { + // file.cs(6,38): warning CS0067: The event 'Test.MyEvent' is never used + // public static event EventHandler MyEvent; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "MyEvent").WithArguments("Test.MyEvent").WithLocation(6, 38) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [Fact] + public void RemoveEventHandler_StaticEvent() + { + string source = @" +using System; + +class Test +{ + public static event EventHandler MyEvent; +} + +class C +{ + void Handler(object sender, EventArgs e) + { + } + + void M() + { + /**/Test.MyEvent -= Handler/**/; + } +} +"; + string expectedOperationTree = @" +IEventAssignmentExpression (EventRemove)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 'Test.MyEvent -= Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (Static) (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 'Test.MyEvent -= Handler') + Instance Receiver: null + Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler') +"; + var expectedDiagnostics = new[] { + // file.cs(6,38): warning CS0067: The event 'Test.MyEvent' is never used + // public static event EventHandler MyEvent; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "MyEvent").WithArguments("Test.MyEvent").WithLocation(6, 38) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [Fact] + public void AddEventHandler_DelegateTypeMismatch() + { + string source = @" +using System; + +class Test +{ + public event EventHandler MyEvent; +} + +class C +{ + void Handler(object sender) + { + } + + void M() + { + var t = new Test(); + /**/t.MyEvent += Handler/**/; + } +} +"; + string expectedOperationTree = @" +IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void, IsInvalid) (Syntax: 't.MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 't.MyEvent += Handler') + Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test, IsInvalid) (Syntax: 't') + Handler: IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler, IsInvalid) (Syntax: 'Handler') + IOperation: (OperationKind.None, IsInvalid) (Syntax: 'Handler') +"; + var expectedDiagnostics = new[] { + // file.cs(18,19): error CS0123: No overload for 'Handler' matches delegate 'EventHandler' + // /**/t.MyEvent += Handler/**/; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "t.MyEvent += Handler").WithArguments("Handler", "System.EventHandler").WithLocation(18, 19), + // file.cs(6,31): warning CS0067: The event 'Test.MyEvent' is never used + // public event EventHandler MyEvent; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "MyEvent").WithArguments("Test.MyEvent").WithLocation(6, 31) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + } +} diff --git a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs index f2ff8f13f9bb5..3884ac466a23f 100644 --- a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs @@ -1458,21 +1458,16 @@ public override TResult Accept(OperationVisitor internal abstract partial class BaseEventAssignmentExpression : Operation, IEventAssignmentExpression { - protected BaseEventAssignmentExpression(IEventSymbol @event, bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : + protected BaseEventAssignmentExpression(bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(OperationKind.EventAssignmentExpression, syntax, type, constantValue) { - Event = @event; Adds = adds; } - /// - /// Event being bound. - /// - public IEventSymbol Event { get; } /// - /// Instance used to refer to the event being bound. + /// Reference to the event being bound. /// - public abstract IOperation EventInstance { get; } + public abstract IEventReferenceExpression EventReference { get; } /// /// Handler supplied for the event. @@ -1487,7 +1482,7 @@ public override IEnumerable Children { get { - yield return EventInstance; + yield return EventReference; yield return HandlerValue; } } @@ -1506,17 +1501,17 @@ public override TResult Accept(OperationVisitor internal sealed partial class EventAssignmentExpression : BaseEventAssignmentExpression, IEventAssignmentExpression { - public EventAssignmentExpression(IEventSymbol @event, IOperation eventInstance, IOperation handlerValue, bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(@event, adds, syntax, type, constantValue) + public EventAssignmentExpression(IEventReferenceExpression eventReference, IOperation handlerValue, bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : + base(adds, syntax, type, constantValue) { - EventInstance = eventInstance; + EventReference = eventReference; HandlerValue = handlerValue; } /// /// Instance used to refer to the event being bound. /// - public override IOperation EventInstance { get; } + public override IEventReferenceExpression EventReference { get; } /// /// Handler supplied for the event. @@ -1529,19 +1524,19 @@ public EventAssignmentExpression(IEventSymbol @event, IOperation eventInstance, /// internal sealed partial class LazyEventAssignmentExpression : BaseEventAssignmentExpression, IEventAssignmentExpression { - private readonly Lazy _lazyEventInstance; + private readonly Lazy _lazyEventReference; private readonly Lazy _lazyHandlerValue; - public LazyEventAssignmentExpression(IEventSymbol @event, Lazy eventInstance, Lazy handlerValue, bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(@event, adds, syntax, type, constantValue) + public LazyEventAssignmentExpression(Lazy eventReference, Lazy handlerValue, bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(adds, syntax, type, constantValue) { - _lazyEventInstance = eventInstance ?? throw new System.ArgumentNullException(nameof(eventInstance)); + _lazyEventReference = eventReference ?? throw new System.ArgumentNullException(nameof(eventReference)); _lazyHandlerValue = handlerValue ?? throw new System.ArgumentNullException(nameof(handlerValue)); } /// /// Instance used to refer to the event being bound. /// - public override IOperation EventInstance => _lazyEventInstance.Value; + public override IEventReferenceExpression EventReference => _lazyEventReference.Value; /// /// Handler supplied for the event. diff --git a/src/Compilers/Core/Portable/Operations/IEventAssignmentExpression.cs b/src/Compilers/Core/Portable/Operations/IEventAssignmentExpression.cs index 6845383637c4b..577a20b253479 100644 --- a/src/Compilers/Core/Portable/Operations/IEventAssignmentExpression.cs +++ b/src/Compilers/Core/Portable/Operations/IEventAssignmentExpression.cs @@ -1,7 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Immutable; - namespace Microsoft.CodeAnalysis.Semantics { /// @@ -14,15 +12,10 @@ namespace Microsoft.CodeAnalysis.Semantics public interface IEventAssignmentExpression : IOperation { /// - /// Event being bound. + /// Reference to the event being bound. /// - IEventSymbol Event { get; } - - /// - /// Instance used to refer to the event being bound. - /// - IOperation EventInstance { get; } - + IEventReferenceExpression EventReference { get; } + /// /// Handler supplied for the event. /// diff --git a/src/Compilers/Core/Portable/Operations/IEventReferenceExpression.cs b/src/Compilers/Core/Portable/Operations/IEventReferenceExpression.cs index ac77aa6aefa4f..0a7e08393aeb6 100644 --- a/src/Compilers/Core/Portable/Operations/IEventReferenceExpression.cs +++ b/src/Compilers/Core/Portable/Operations/IEventReferenceExpression.cs @@ -1,7 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Immutable; - namespace Microsoft.CodeAnalysis.Semantics { /// diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 10a1fd6177789..e10369e56348c 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -405,8 +405,7 @@ Microsoft.CodeAnalysis.Semantics.IEmptyStatement Microsoft.CodeAnalysis.Semantics.IEndStatement Microsoft.CodeAnalysis.Semantics.IEventAssignmentExpression Microsoft.CodeAnalysis.Semantics.IEventAssignmentExpression.Adds.get -> bool -Microsoft.CodeAnalysis.Semantics.IEventAssignmentExpression.Event.get -> Microsoft.CodeAnalysis.IEventSymbol -Microsoft.CodeAnalysis.Semantics.IEventAssignmentExpression.EventInstance.get -> Microsoft.CodeAnalysis.IOperation +Microsoft.CodeAnalysis.Semantics.IEventAssignmentExpression.EventReference.get -> Microsoft.CodeAnalysis.Semantics.IEventReferenceExpression Microsoft.CodeAnalysis.Semantics.IEventAssignmentExpression.HandlerValue.get -> Microsoft.CodeAnalysis.IOperation Microsoft.CodeAnalysis.Semantics.IEventReferenceExpression Microsoft.CodeAnalysis.Semantics.IEventReferenceExpression.Event.get -> Microsoft.CodeAnalysis.IEventSymbol diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb index aae8e40ff6434..42ffd38cc6cc5 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb @@ -408,20 +408,16 @@ Namespace Microsoft.CodeAnalysis.Semantics Private Function GetAddHandlerStatementExpression(statement As BoundAddHandlerStatement) As IOperation Dim eventAccess As BoundEventAccess = TryCast(statement.EventAccess, BoundEventAccess) - Dim [event] As IEventSymbol = eventAccess?.EventSymbol - Dim instance = If([event] Is Nothing OrElse [event].IsStatic, Nothing, If(eventAccess IsNot Nothing, Create(eventAccess.ReceiverOpt), Nothing)) - + Dim eventReference = If(eventAccess Is Nothing, Nothing, CreateBoundEventAccessOperation(eventAccess)) Return New EventAssignmentExpression( - [event], instance, Create(statement.Handler), adds:=True, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) + eventReference, Create(statement.Handler), adds:=True, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) End Function Private Function GetRemoveStatementExpression(statement As BoundRemoveHandlerStatement) As IOperation Dim eventAccess As BoundEventAccess = TryCast(statement.EventAccess, BoundEventAccess) - Dim [event] As IEventSymbol = eventAccess?.EventSymbol - Dim instance = If([event] Is Nothing OrElse [event].IsStatic, Nothing, If(eventAccess IsNot Nothing, Create(eventAccess.ReceiverOpt), Nothing)) - + Dim eventReference = If(eventAccess Is Nothing, Nothing, CreateBoundEventAccessOperation(eventAccess)) Return New EventAssignmentExpression( - [event], instance, Create(statement.Handler), adds:=False, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) + eventReference, Create(statement.Handler), adds:=False, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) End Function Private Shared Function GetConversionKind(kind As VisualBasic.ConversionKind) As Semantics.ConversionKind diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb new file mode 100644 index 0000000000000..b20e14785041b --- /dev/null +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb @@ -0,0 +1,173 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics + + Partial Public Class IOperationTests + Inherits SemanticModelTestBase + + + Public Sub AddEventHandler() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of AddRemoveHandlerStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + Public Sub RemoveEventHandler() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of AddRemoveHandlerStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + Public Sub AddEventHandler_StaticEvent() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of AddRemoveHandlerStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + Public Sub RemoveEventHandler_StaticEvent() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of AddRemoveHandlerStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + Public Sub RemoveEventHandler_DelegateTypeMismatch() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = .Value + VerifyOperationTreeAndDiagnosticsForTest(Of AddRemoveHandlerStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + End Class +End Namespace diff --git a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs index f568ce544efce..21a4e1c06e6d3 100644 --- a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs +++ b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs @@ -724,11 +724,10 @@ public override void VisitEventAssignmentExpression(IEventAssignmentExpression o { var kindStr = operation.Adds ? "EventAdd" : "EventRemove"; LogString($"{nameof(IEventAssignmentExpression)} ({kindStr})"); - LogSymbol(operation.Event, header: " (Event: "); LogString(")"); LogCommonPropertiesAndNewLine(operation); - Visit(operation.EventInstance, header: "Event Instance"); + Visit(operation.EventReference, header: "Event Reference"); Visit(operation.HandlerValue, header: "Handler"); } diff --git a/src/Test/Utilities/Portable/Compilation/TestOperationWalker.cs b/src/Test/Utilities/Portable/Compilation/TestOperationWalker.cs index 9cfceaeedb903..6d088d751fd4f 100644 --- a/src/Test/Utilities/Portable/Compilation/TestOperationWalker.cs +++ b/src/Test/Utilities/Portable/Compilation/TestOperationWalker.cs @@ -302,7 +302,6 @@ public override void VisitEventReferenceExpression(IEventReferenceExpression ope public override void VisitEventAssignmentExpression(IEventAssignmentExpression operation) { - var eventSymbol = operation.Event; var adds = operation.Adds; base.VisitEventAssignmentExpression(operation); diff --git a/src/Test/Utilities/Portable/Diagnostics/OperationTestAnalyzer.cs b/src/Test/Utilities/Portable/Diagnostics/OperationTestAnalyzer.cs index 86d9d6e037568..715f41285e66b 100644 --- a/src/Test/Utilities/Portable/Diagnostics/OperationTestAnalyzer.cs +++ b/src/Test/Utilities/Portable/Diagnostics/OperationTestAnalyzer.cs @@ -1060,9 +1060,9 @@ public sealed override void Initialize(AnalysisContext context) IEventAssignmentExpression eventAssignment = (IEventAssignmentExpression)operationContext.Operation; operationContext.ReportDiagnostic(Diagnostic.Create(eventAssignment.Adds ? HandlerAddedDescriptor : HandlerRemovedDescriptor, operationContext.Operation.Syntax.GetLocation())); - if (eventAssignment.Event == null) + if (eventAssignment.EventReference?.Event == null) { - if (eventAssignment.EventInstance == null && eventAssignment.HasErrors(operationContext.Compilation, operationContext.CancellationToken)) + if (eventAssignment.EventReference?.Instance == null && eventAssignment.HasErrors(operationContext.Compilation, operationContext.CancellationToken)) { // report inside after checking for null to make sure it does't crash. operationContext.ReportDiagnostic(Diagnostic.Create(InvalidEventDescriptor, eventAssignment.Syntax.GetLocation())); @@ -1425,10 +1425,6 @@ public sealed override void Initialize(AnalysisContext context) memberSymbol = ((IInvocationExpression)operation).TargetMethod; receiver = ((IInvocationExpression)operation).Instance; break; - case OperationKind.EventAssignmentExpression: - memberSymbol = ((IEventAssignmentExpression)operation).Event; - receiver = ((IEventAssignmentExpression)operation).EventInstance; - break; default: throw new ArgumentException(); } @@ -1446,8 +1442,7 @@ public sealed override void Initialize(AnalysisContext context) OperationKind.PropertyReferenceExpression, OperationKind.EventReferenceExpression, OperationKind.MethodBindingExpression, - OperationKind.InvocationExpression, - OperationKind.EventAssignmentExpression); + OperationKind.InvocationExpression); } } From 6a1c9675c88e44f0a3bde344f9e0db7b42c326a7 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Thu, 20 Jul 2017 18:25:20 -0700 Subject: [PATCH 02/11] Fix syntax node for the EventReference in IEventAssignmentOperation --- .../Operations/CSharpOperationFactory.cs | 17 +++++++++-------- .../Diagnostics/OperationAnalyzerTests.cs | 4 ++-- ...OperationTests_IEventAssignmentExpression.cs | 10 +++++----- .../Operations/VisualBasicOperationFactory.vb | 4 ++-- .../VisualBasicOperationFactory_Methods.vb | 12 +++--------- ...OperationTests_IEventAssignmentExpression.vb | 10 +++++----- 6 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 988a88ea6e8dd..ba48ce10a9054 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -7,6 +7,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -358,16 +359,16 @@ private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(B SyntaxNode syntax = boundEventAssignmentOperator.Syntax; Lazy eventReference = new Lazy(() => { + // BoundEventAssignmentOperator doesn't hold on to BoundEventAccess provided during binding. + // Based on the implementation of those two bound node types, the following data can be retrieved w/o changing BoundEventAssignmentOperator: + // 1. the type of BoundEventAccess is the type of the event symbol. + // 2. the constant value of BoundEventAccess is always null. + // 3. the syntax of the boundEventAssignmentOperator is always AssignmentExpressionSyntax, so the syntax for the event reference would be the LHS of the assignment. IEventSymbol @event = boundEventAssignmentOperator.Event; Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.Event.IsStatic ? null : boundEventAssignmentOperator.ReceiverOpt)); - ISymbol member = boundEventAssignmentOperator.Event; - // BoundEventAssignmentOperator doesn't hold on to all the data from the provided BoundEventAccess during binding. - // Based on the implementation of those two bound node types, the following data can be retieved w/o changing BoundEventAssignmentOperator: - // 1. The type of BoundEventAccess is the type of the event symbol. - // 2. the constant value of BoundEventAccess is always null. - // However, we can't reliably get the syntax node for the BoundEventAccess w/o changing BoundEventAssignmentOperator, so the syntax of entire - // BoundEventAssignmentOperator is used instead. - return new LazyEventReferenceExpression(@event, instance, @event, syntax, @event.Type, ConvertToOptional(null)); + SyntaxNode eventAccessSyntax = ((AssignmentExpressionSyntax)syntax).Left; + + return new LazyEventReferenceExpression(@event, instance, @event, eventAccessSyntax, @event.Type, ConvertToOptional(null)); }); Lazy handlerValue = new Lazy(() => Create(boundEventAssignmentOperator.Argument)); diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs index a6bb5bb7d7a04..54cce5df8298e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs @@ -1485,11 +1485,11 @@ void Foo() CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularWithIOperationFeature) .VerifyDiagnostics(Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("D.E").WithLocation(6, 32)) .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new StaticMemberTestAnalyzer() }, null, null, false, - Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "C.E += D.Method").WithLocation(23, 9), + Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "C.E").WithLocation(23, 9), Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "D.Method").WithLocation(23, 16), Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "C.E").WithLocation(24, 9), Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "C.Bar()").WithLocation(25, 9), - Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "D.E += () => { }").WithLocation(27, 9), + Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "D.E").WithLocation(27, 9), Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "D.Field").WithLocation(28, 9), Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "D.Property").WithLocation(29, 17), Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "D.Method()").WithLocation(30, 9) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs index 09991493348d2..34b0ecfefea05 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs @@ -33,7 +33,7 @@ void M() "; string expectedOperationTree = @" IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 't.MyEvent += Handler') - Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 't.MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 't.MyEvent') Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test) (Syntax: 't') Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler') @@ -69,7 +69,7 @@ void M() "; string expectedOperationTree = @" IEventAssignmentExpression (EventRemove)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 't.MyEvent -= null') - Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 't.MyEvent -= null') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 't.MyEvent') Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test) (Syntax: 't') Handler: IConversionExpression (ConversionKind.Cast, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler, Constant: null) (Syntax: 'null') ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: null, Constant: null) (Syntax: 'null') @@ -108,7 +108,7 @@ void M() "; string expectedOperationTree = @" IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 'Test.MyEvent += Handler') - Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (Static) (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 'Test.MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (Static) (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 'Test.MyEvent') Instance Receiver: null Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler') @@ -147,7 +147,7 @@ void M() "; string expectedOperationTree = @" IEventAssignmentExpression (EventRemove)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 'Test.MyEvent -= Handler') - Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (Static) (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 'Test.MyEvent -= Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (Static) (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 'Test.MyEvent') Instance Receiver: null Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler') @@ -187,7 +187,7 @@ void M() "; string expectedOperationTree = @" IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void, IsInvalid) (Syntax: 't.MyEvent += Handler') - Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 't.MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 't.MyEvent') Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test, IsInvalid) (Syntax: 't') Handler: IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler, IsInvalid) (Syntax: 'Handler') IOperation: (OperationKind.None, IsInvalid) (Syntax: 'Handler') diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb index f85acf40829e9..082d4b415f817 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb @@ -1011,7 +1011,7 @@ Namespace Microsoft.CodeAnalysis.Semantics End Function Private Function CreateBoundAddHandlerStatementOperation(boundAddHandlerStatement As BoundAddHandlerStatement) As IExpressionStatement - Dim expression As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() GetAddHandlerStatementExpression(boundAddHandlerStatement)) + Dim expression As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() GetAddRemoveHandlerStatementExpression(boundAddHandlerStatement)) Dim syntax As SyntaxNode = boundAddHandlerStatement.Syntax Dim type As ITypeSymbol = Nothing Dim constantValue As [Optional](Of Object) = New [Optional](Of Object)() @@ -1019,7 +1019,7 @@ Namespace Microsoft.CodeAnalysis.Semantics End Function Private Function CreateBoundRemoveHandlerStatementOperation(boundRemoveHandlerStatement As BoundRemoveHandlerStatement) As IExpressionStatement - Dim expression As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() GetRemoveStatementExpression(boundRemoveHandlerStatement)) + Dim expression As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() GetAddRemoveHandlerStatementExpression(boundRemoveHandlerStatement)) Dim syntax As SyntaxNode = boundRemoveHandlerStatement.Syntax Dim type As ITypeSymbol = Nothing Dim constantValue As [Optional](Of Object) = New [Optional](Of Object)() diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb index 42ffd38cc6cc5..66542b99b4fc3 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb @@ -406,18 +406,12 @@ Namespace Microsoft.CodeAnalysis.Semantics constantValue:=Nothing) End Function - Private Function GetAddHandlerStatementExpression(statement As BoundAddHandlerStatement) As IOperation + Private Function GetAddRemoveHandlerStatementExpression(statement As BoundAddRemoveHandlerStatement) As IOperation Dim eventAccess As BoundEventAccess = TryCast(statement.EventAccess, BoundEventAccess) Dim eventReference = If(eventAccess Is Nothing, Nothing, CreateBoundEventAccessOperation(eventAccess)) + Dim adds = TypeOf statement Is BoundAddHandlerStatement Return New EventAssignmentExpression( - eventReference, Create(statement.Handler), adds:=True, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) - End Function - - Private Function GetRemoveStatementExpression(statement As BoundRemoveHandlerStatement) As IOperation - Dim eventAccess As BoundEventAccess = TryCast(statement.EventAccess, BoundEventAccess) - Dim eventReference = If(eventAccess Is Nothing, Nothing, CreateBoundEventAccessOperation(eventAccess)) - Return New EventAssignmentExpression( - eventReference, Create(statement.Handler), adds:=False, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) + eventReference, Create(statement.Handler), adds:=adds, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) End Function Private Shared Function GetConversionKind(kind As VisualBasic.ConversionKind) As Semantics.ConversionKind diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb index b20e14785041b..d1bde51be6d7d 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb @@ -16,7 +16,7 @@ Class TestClass Event TestEvent As Action - Sub Add(receiver As TestClass) + Sub Add() AddHandler TestEvent, AddressOf M'BIND:"AddHandler TestEvent, AddressOf M" End Sub @@ -48,7 +48,7 @@ Class TestClass Event TestEvent As Action - Sub Remove(receiver As TestClass) + Sub Remove() RemoveHandler TestEvent, AddressOf M'BIND:"RemoveHandler TestEvent, AddressOf M" End Sub @@ -80,7 +80,7 @@ Class TestClass Shared Event TestEvent As Action - Sub Add(receiver As TestClass) + Sub Add() AddHandler TestEvent, AddressOf M'BIND:"AddHandler TestEvent, AddressOf M" End Sub @@ -112,7 +112,7 @@ Class TestClass Shared Event TestEvent As Action - Sub Remove(receiver As TestClass) + Sub Remove() RemoveHandler TestEvent, AddressOf M'BIND:"RemoveHandler TestEvent, AddressOf M" End Sub @@ -144,7 +144,7 @@ Class TestClass Shared Event TestEvent As Action - Sub Remove(receiver As TestClass) + Sub Remove() RemoveHandler TestEvent, AddressOf M'BIND:"RemoveHandler TestEvent, AddressOf M" End Sub From a9117b7b1c6aa810f296524830476c9d90cd2f97 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Fri, 21 Jul 2017 12:05:57 -0700 Subject: [PATCH 03/11] Fix tests after rebase --- ...erationTests_IEventAssignmentExpression.cs | 4 +- ...erationTests_IEventAssignmentExpression.vb | 58 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs index 34b0ecfefea05..c09a64b2463ca 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs @@ -72,7 +72,7 @@ void M() Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 't.MyEvent') Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test) (Syntax: 't') Handler: IConversionExpression (ConversionKind.Cast, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler, Constant: null) (Syntax: 'null') - ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: null, Constant: null) (Syntax: 'null') + Operand: ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: null, Constant: null) (Syntax: 'null') "; var expectedDiagnostics = new[] { // file.cs(6,31): warning CS0067: The event 'Test.MyEvent' is never used @@ -190,7 +190,7 @@ void M() Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 't.MyEvent') Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test, IsInvalid) (Syntax: 't') Handler: IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler, IsInvalid) (Syntax: 'Handler') - IOperation: (OperationKind.None, IsInvalid) (Syntax: 'Handler') + Operand: IOperation: (OperationKind.None, IsInvalid) (Syntax: 'Handler') "; var expectedDiagnostics = new[] { // file.cs(18,19): error CS0123: No overload for 'Handler' matches delegate 'EventHandler' diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb index d1bde51be6d7d..3ae0ea6ddd030 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb @@ -26,12 +26,12 @@ End Class]]>.Value Dim expectedOperationTree = .Value Dim expectedDiagnostics = String.Empty @@ -58,12 +58,12 @@ End Class]]>.Value Dim expectedOperationTree = .Value Dim expectedDiagnostics = String.Empty @@ -90,12 +90,12 @@ End Class]]>.Value Dim expectedOperationTree = .Value Dim expectedDiagnostics = String.Empty @@ -122,12 +122,12 @@ End Class]]>.Value Dim expectedOperationTree = .Value Dim expectedDiagnostics = String.Empty @@ -154,11 +154,11 @@ End Class]]>.Value Dim expectedOperationTree = .Value Dim expectedDiagnostics = Date: Fri, 28 Jul 2017 10:31:39 -0700 Subject: [PATCH 04/11] Address review comments --- .../Diagnostics/OperationAnalyzerTests.cs | 15 ++++++-------- .../VisualBasicOperationFactory_Methods.vb | 2 +- .../Diagnostics/OperationAnalyzerTests.vb | 20 ++++++++++--------- .../Diagnostics/OperationTestAnalyzer.cs | 8 ++------ 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs index 54cce5df8298e..3c7ce52d898ab 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs @@ -1125,7 +1125,7 @@ public override void M1() ); } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/18839")] + [Fact] public void EventAndMethodReferencesCSharp() { const string source = @" @@ -1154,21 +1154,18 @@ private void Mumbler(object sender, System.EventArgs args) CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularWithIOperationFeature) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new MemberReferenceAnalyzer() }, null, null, false, + // Bug: we are missing diagnostics of "MethodBindingDescriptor" here. https://github.com/dotnet/roslyn/issues/20095 Diagnostic(MemberReferenceAnalyzer.HandlerAddedDescriptor.Id, "Mumble += new MumbleEventHandler(Mumbler)").WithLocation(10, 9), - // Bug: Missing a EventReferenceExpression here https://github.com/dotnet/roslyn/issues/8346 - Diagnostic(MemberReferenceAnalyzer.MethodBindingDescriptor.Id, "Mumbler").WithLocation(10, 42), + Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(10, 9), Diagnostic(MemberReferenceAnalyzer.HandlerAddedDescriptor.Id, "Mumble += (s, a) => {}").WithLocation(11, 9), - // Bug: Missing a EventReferenceExpression here https://github.com/dotnet/roslyn/issues/8346 + Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(11, 9), Diagnostic(MemberReferenceAnalyzer.HandlerAddedDescriptor.Id, "Mumble += new MumbleEventHandler((s, a) => {})").WithLocation(12, 9), - // Bug: Missing a EventReferenceExpression here https://github.com/dotnet/roslyn/issues/8346 - Diagnostic(MemberReferenceAnalyzer.MethodBindingDescriptor.Id, "(s, a) => {}").WithLocation(12, 42), // Bug: this is not a method binding https://github.com/dotnet/roslyn/issues/8347 + Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(12, 9), Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(13, 9), Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(14, 20), Diagnostic(MemberReferenceAnalyzer.MethodBindingDescriptor.Id, "Mumbler").WithLocation(15, 32), Diagnostic(MemberReferenceAnalyzer.HandlerRemovedDescriptor.Id, "Mumble -= new MumbleEventHandler(Mumbler)").WithLocation(17, 9), - // Bug: Missing a EventReferenceExpression here https://github.com/dotnet/roslyn/issues/8346 - Diagnostic(MemberReferenceAnalyzer.MethodBindingDescriptor.Id, "Mumbler").WithLocation(17, 42) - ); + Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(17, 9)); } [Fact] diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb index 66542b99b4fc3..5f96ac81ae4a9 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb @@ -409,7 +409,7 @@ Namespace Microsoft.CodeAnalysis.Semantics Private Function GetAddRemoveHandlerStatementExpression(statement As BoundAddRemoveHandlerStatement) As IOperation Dim eventAccess As BoundEventAccess = TryCast(statement.EventAccess, BoundEventAccess) Dim eventReference = If(eventAccess Is Nothing, Nothing, CreateBoundEventAccessOperation(eventAccess)) - Dim adds = TypeOf statement Is BoundAddHandlerStatement + Dim adds = statement.Kind = BoundKind.AddHandlerStatement Return New EventAssignmentExpression( eventReference, Create(statement.Handler), adds:=adds, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) End Function diff --git a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb index 311b789a4c1f2..f565ff1d45fa0 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb @@ -1146,7 +1146,7 @@ End Class Diagnostic(ExplicitVsImplicitInstanceAnalyzer.ImplicitInstanceDescriptor.Id, "M2").WithLocation(15, 9)) End Sub - + Public Sub EventAndMethodReferencesVisualBasic() Dim source = @@ -1178,17 +1178,19 @@ End Class Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source, parseOptions:=TestOptions.RegularWithIOperationFeature) comp.VerifyDiagnostics() - comp.VerifyAnalyzerDiagnostics({New MemberReferenceAnalyzer}, Nothing, Nothing, False, - Diagnostic(MemberReferenceAnalyzer.HandlerAddedDescriptor.Id, "AddHandler Mumble, New MumbleEventHandler(AddressOf Mumbler)").WithLocation(7, 9), ' Bug: Missing a EventReferenceExpression here https://github.com/dotnet/roslyn/issues/8346 - Diagnostic(MemberReferenceAnalyzer.MethodBindingDescriptor.Id, "AddressOf Mumbler").WithLocation(7, 51), + comp.VerifyAnalyzerDiagnostics({New MemberReferenceAnalyzer}, Nothing, Nothing, False, ' Bug: we are missing diagnostics of "MethodBindingDescriptor" here. https://github.com/dotnet/roslyn/issues/20095 + Diagnostic(MemberReferenceAnalyzer.HandlerAddedDescriptor.Id, "AddHandler Mumble, New MumbleEventHandler(AddressOf Mumbler)").WithLocation(7, 9), + Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(7, 20), Diagnostic(MemberReferenceAnalyzer.HandlerAddedDescriptor.Id, "AddHandler Mumble, New MumbleEventHandler(Sub(s As Object, a As System.EventArgs) - End Sub)").WithLocation(8, 9), ' Bug: Missing a EventReferenceExpression here https://github.com/dotnet/roslyn/issues/8346 + End Sub)").WithLocation(8, 9), + Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(8, 20), Diagnostic(MemberReferenceAnalyzer.HandlerAddedDescriptor.Id, "AddHandler Mumble, Sub(s As Object, a As System.EventArgs) - End Sub").WithLocation(10, 9), ' Bug: Missing a EventReferenceExpression here https://github.com/dotnet/roslyn/issues/8346 + End Sub").WithLocation(10, 9), + Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(10, 20), Diagnostic(MemberReferenceAnalyzer.FieldReferenceDescriptor.Id, "Mumble").WithLocation(12, 20), ' Bug: This should be an event reference. https://github.com/dotnet/roslyn/issues/8345 - Diagnostic(MemberReferenceAnalyzer.MethodBindingDescriptor.Id, "AddressOf Mumbler").WithLocation(14, 39), - Diagnostic(MemberReferenceAnalyzer.HandlerRemovedDescriptor.Id, "RemoveHandler Mumble, AddressOf Mumbler").WithLocation(16, 9), ' Bug: Missing a EventReferenceExpression here https://github.com/dotnet/roslyn/issues/8346 - Diagnostic(MemberReferenceAnalyzer.MethodBindingDescriptor.Id, "AddressOf Mumbler").WithLocation(16, 31)) + Diagnostic(MemberReferenceAnalyzer.HandlerRemovedDescriptor.Id, "RemoveHandler Mumble, AddressOf Mumbler").WithLocation(16, 9), + Diagnostic(MemberReferenceAnalyzer.EventReferenceDescriptor.Id, "Mumble").WithLocation(16, 23) + ) End Sub diff --git a/src/Test/Utilities/Portable/Diagnostics/OperationTestAnalyzer.cs b/src/Test/Utilities/Portable/Diagnostics/OperationTestAnalyzer.cs index 715f41285e66b..7e9d46b9617ce 100644 --- a/src/Test/Utilities/Portable/Diagnostics/OperationTestAnalyzer.cs +++ b/src/Test/Utilities/Portable/Diagnostics/OperationTestAnalyzer.cs @@ -1060,13 +1060,9 @@ public sealed override void Initialize(AnalysisContext context) IEventAssignmentExpression eventAssignment = (IEventAssignmentExpression)operationContext.Operation; operationContext.ReportDiagnostic(Diagnostic.Create(eventAssignment.Adds ? HandlerAddedDescriptor : HandlerRemovedDescriptor, operationContext.Operation.Syntax.GetLocation())); - if (eventAssignment.EventReference?.Event == null) + if (eventAssignment.EventReference?.Event == null && eventAssignment.HasErrors(operationContext.Compilation, operationContext.CancellationToken)) { - if (eventAssignment.EventReference?.Instance == null && eventAssignment.HasErrors(operationContext.Compilation, operationContext.CancellationToken)) - { - // report inside after checking for null to make sure it does't crash. - operationContext.ReportDiagnostic(Diagnostic.Create(InvalidEventDescriptor, eventAssignment.Syntax.GetLocation())); - } + operationContext.ReportDiagnostic(Diagnostic.Create(InvalidEventDescriptor, eventAssignment.Syntax.GetLocation())); } }, OperationKind.EventAssignmentExpression); From 0e0e4efd80ea620c23aeadc93a1adda5817b6d3e Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Fri, 28 Jul 2017 12:55:23 -0700 Subject: [PATCH 05/11] Fix a failed test --- .../IOperationTests_IForLoopStatement.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.cs index f6126bc734227..fab997bfd60ec 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.cs @@ -1247,24 +1247,24 @@ public void Next() string expectedOperationTree = @" IForLoopStatement (LoopKind.For) (OperationKind.LoopStatement) (Syntax: 'for (d.Init ... }') Condition: IUnaryOperatorExpression (UnaryOperationKind.DynamicTrue) (OperationKind.UnaryOperatorExpression, Type: System.Boolean) (Syntax: 'd.Done') - Operand: IOperation: (OperationKind.None) (Syntax: 'd.Done') - Children(1): - ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic) (Syntax: 'd') + Operand: IDynamicMemberReferenceExpression (Member Name: ""Done"", Containing Type: null) (OperationKind.DynamicMemberReferenceExpression, Type: dynamic) (Syntax: 'd.Done') + Type Arguments(0) + Instance Receiver: ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic) (Syntax: 'd') Before: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'd.Initialize(5)') Expression: IOperation: (OperationKind.None) (Syntax: 'd.Initialize(5)') Children(2): - IOperation: (OperationKind.None) (Syntax: 'd.Initialize') - Children(1): - ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic) (Syntax: 'd') + IDynamicMemberReferenceExpression (Member Name: ""Initialize"", Containing Type: null) (OperationKind.DynamicMemberReferenceExpression, Type: dynamic) (Syntax: 'd.Initialize') + Type Arguments(0) + Instance Receiver: ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic) (Syntax: 'd') ILiteralExpression (Text: 5) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 5) (Syntax: '5') AtLoopBottom: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'd.Next()') Expression: IOperation: (OperationKind.None) (Syntax: 'd.Next()') Children(1): - IOperation: (OperationKind.None) (Syntax: 'd.Next') - Children(1): - ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic) (Syntax: 'd') + IDynamicMemberReferenceExpression (Member Name: ""Next"", Containing Type: null) (OperationKind.DynamicMemberReferenceExpression, Type: dynamic) (Syntax: 'd.Next') + Type Arguments(0) + Instance Receiver: ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic) (Syntax: 'd') Body: IBlockStatement (0 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }') "; VerifyOperationTreeForTest(source, expectedOperationTree); From d500d5212cc11ae2b7f5d089093fe561ca6d8010 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Mon, 31 Jul 2017 14:33:28 -0700 Subject: [PATCH 06/11] Expose receiver for static event assignemt --- .../Operations/CSharpOperationFactory.cs | 2 +- ...erationTests_IEventAssignmentExpression.cs | 43 +++++++++++++++++++ .../Operations/VisualBasicOperationFactory.vb | 6 +-- ...erationTests_IEventAssignmentExpression.vb | 34 +++++++++++++++ 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index ba48ce10a9054..33fd7d2a4f611 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -365,7 +365,7 @@ private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(B // 2. the constant value of BoundEventAccess is always null. // 3. the syntax of the boundEventAssignmentOperator is always AssignmentExpressionSyntax, so the syntax for the event reference would be the LHS of the assignment. IEventSymbol @event = boundEventAssignmentOperator.Event; - Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.Event.IsStatic ? null : boundEventAssignmentOperator.ReceiverOpt)); + Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.ReceiverOpt)); SyntaxNode eventAccessSyntax = ((AssignmentExpressionSyntax)syntax).Left; return new LazyEventReferenceExpression(@event, instance, @event, eventAccessSyntax, @event.Type, ConvertToOptional(null)); diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs index c09a64b2463ca..ded5831b5f260 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs @@ -203,5 +203,48 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + + [Fact] + public void AddEventHandler_AssignToStaticEventOnInstance() + { + string source = @" +using System; + +class Test +{ + public static event EventHandler MyEvent; +} + +class C +{ + void Handler(object sender, EventArgs e) + { + } + + void M() + { + var t = new Test(); + /**/t.MyEvent += Handler/**/; + } +} +"; + string expectedOperationTree = @" +IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void, IsInvalid) (Syntax: 't.MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 't.MyEvent') + Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test, IsInvalid) (Syntax: 't') + Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler') +"; + var expectedDiagnostics = new[] { + // file.cs(18,19): error CS0176: Member 'Test.MyEvent' cannot be accessed with an instance reference; qualify it with a type name instead + // /**/t.MyEvent += Handler/**/; + Diagnostic(ErrorCode.ERR_ObjectProhibited, "t.MyEvent").WithArguments("Test.MyEvent").WithLocation(18, 19), + // file.cs(6,38): warning CS0067: The event 'Test.MyEvent' is never used + // public static event EventHandler MyEvent; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "MyEvent").WithArguments("Test.MyEvent").WithLocation(6, 38) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } } } diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb index 082d4b415f817..ebc5cd60c9c08 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb @@ -574,11 +574,7 @@ Namespace Microsoft.CodeAnalysis.Semantics Private Function CreateBoundEventAccessOperation(boundEventAccess As BoundEventAccess) As IEventReferenceExpression Dim instance As Lazy(Of IOperation) = New Lazy(Of IOperation)( Function() - If boundEventAccess.EventSymbol.IsShared Then - Return Nothing - Else - Return Create(boundEventAccess.ReceiverOpt) - End If + Return Create(boundEventAccess.ReceiverOpt) End Function) Dim [event] As IEventSymbol = boundEventAccess.EventSymbol diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb index 3ae0ea6ddd030..2b1f9776f1ffb 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb @@ -169,5 +169,39 @@ BC31143: Method 'Public Sub M(x As Integer)' does not have a signature compatibl VerifyOperationTreeAndDiagnosticsForTest(Of AddRemoveHandlerStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) End Sub + + Public Sub AddEventHandler_AssignToSharedEventOnInstance() + Dim source = .Value + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = .Value + VerifyOperationTreeAndDiagnosticsForTest(Of AddRemoveHandlerStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + End Class End Namespace From f8bf025342d63b39652caa38016aa56525dd944c Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 1 Aug 2017 14:10:13 -0700 Subject: [PATCH 07/11] Reverted the change for receiver in static event assignment and add more tests --- .../Operations/CSharpOperationFactory.cs | 2 +- ...erationTests_IEventAssignmentExpression.cs | 82 ++++++++++++++++++- .../Operations/VisualBasicOperationFactory.vb | 6 +- ...erationTests_IEventAssignmentExpression.vb | 39 ++++++++- 4 files changed, 123 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 33fd7d2a4f611..ba48ce10a9054 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -365,7 +365,7 @@ private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(B // 2. the constant value of BoundEventAccess is always null. // 3. the syntax of the boundEventAssignmentOperator is always AssignmentExpressionSyntax, so the syntax for the event reference would be the LHS of the assignment. IEventSymbol @event = boundEventAssignmentOperator.Event; - Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.ReceiverOpt)); + Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.Event.IsStatic ? null : boundEventAssignmentOperator.ReceiverOpt)); SyntaxNode eventAccessSyntax = ((AssignmentExpressionSyntax)syntax).Left; return new LazyEventReferenceExpression(@event, instance, @event, eventAccessSyntax, @event.Type, ConvertToOptional(null)); diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs index ded5831b5f260..dadf86ac06b64 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.CodeAnalysis.CSharp.Syntax; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests @@ -230,8 +231,8 @@ void M() "; string expectedOperationTree = @" IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void, IsInvalid) (Syntax: 't.MyEvent += Handler') - Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 't.MyEvent') - Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test, IsInvalid) (Syntax: 't') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (Static) (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 't.MyEvent') + Instance Receiver: null Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler') "; @@ -246,5 +247,82 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + + [Fact] + [WorkItem(8909, "https://github.com/dotnet/roslyn/issues/8909")] + public void AddEventHandler_AssignToNonStaticEventOnType() + { + string source = @" +using System; + +class Test +{ + public event EventHandler MyEvent; +} + +class C +{ + void Handler(object sender, EventArgs e) + { + } + + void M() + { + /**/Test.MyEvent += Handler/**/; + } +} +"; + string expectedOperationTree = @" +IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void, IsInvalid) (Syntax: 'Test.MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 'Test.MyEvent') + Instance Receiver: IOperation: (OperationKind.None, IsInvalid) (Syntax: 'Test') + Handler: IMethodBindingExpression: void C.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'Handler')"; + var expectedDiagnostics = new[] { + // file.cs(17,19): error CS0120: An object reference is required for the non-static field, method, or property 'Test.MyEvent' + // /**/Test.MyEvent += Handler/**/; + Diagnostic(ErrorCode.ERR_ObjectRequired, "Test.MyEvent").WithArguments("Test.MyEvent").WithLocation(17, 19), + // file.cs(6,31): warning CS0067: The event 'Test.MyEvent' is never used + // public event EventHandler MyEvent; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "MyEvent").WithArguments("Test.MyEvent").WithLocation(6, 31) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [Fact] + public void AddEventHandler_AssignToEventWithoutExplicitReceiver() + { + string source = @" +using System; + +class Test +{ + public event EventHandler MyEvent; + + void Handler(object sender, EventArgs e) + { + } + + void M() + { + /**/MyEvent += Handler/**/; + } +} +"; + string expectedOperationTree = @" +IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 'MyEvent += Handler') + Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 'MyEvent') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Test) (Syntax: 'MyEvent') + Handler: IMethodBindingExpression: void Test.Handler(System.Object sender, System.EventArgs e) (OperationKind.MethodBindingExpression, Type: System.EventHandler) (Syntax: 'Handler') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Test) (Syntax: 'Handler')"; + var expectedDiagnostics = new[] { + // file.cs(6,31): warning CS0067: The event 'Test.MyEvent' is never used + // public event EventHandler MyEvent; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "MyEvent").WithArguments("Test.MyEvent").WithLocation(6, 31) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } } } diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb index ebc5cd60c9c08..082d4b415f817 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb @@ -574,7 +574,11 @@ Namespace Microsoft.CodeAnalysis.Semantics Private Function CreateBoundEventAccessOperation(boundEventAccess As BoundEventAccess) As IEventReferenceExpression Dim instance As Lazy(Of IOperation) = New Lazy(Of IOperation)( Function() - Return Create(boundEventAccess.ReceiverOpt) + If boundEventAccess.EventSymbol.IsShared Then + Return Nothing + Else + Return Create(boundEventAccess.ReceiverOpt) + End If End Function) Dim [event] As IEventSymbol = boundEventAccess.EventSymbol diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb index 2b1f9776f1ffb..6d15786445a19 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb @@ -1,6 +1,7 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -188,8 +189,8 @@ End Class]]>.Value Dim expectedOperationTree = + + Public Sub AddEventHandler_AssignToNonSharedEventOnType() + Dim source = .Value + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = .Value + VerifyOperationTreeAndDiagnosticsForTest(Of AddRemoveHandlerStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub End Class End Namespace From ab14b7769a65f02cd44bf131a3644369ba7222a2 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 1 Aug 2017 17:39:13 -0700 Subject: [PATCH 08/11] extract method for creating event reference --- .../Operations/CSharpOperationFactory.cs | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index a1fbe37df8064..469532b60bca0 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -354,24 +354,26 @@ private IEventReferenceExpression CreateBoundEventAccessOperation(BoundEventAcce return new LazyEventReferenceExpression(@event, instance, member, syntax, type, constantValue); } - private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(BoundEventAssignmentOperator boundEventAssignmentOperator) + private IEventReferenceExpression CreateBoundEventAccessOperation(BoundEventAssignmentOperator boundEventAssignmentOperator) { SyntaxNode syntax = boundEventAssignmentOperator.Syntax; - Lazy eventReference = new Lazy(() => - { - // BoundEventAssignmentOperator doesn't hold on to BoundEventAccess provided during binding. - // Based on the implementation of those two bound node types, the following data can be retrieved w/o changing BoundEventAssignmentOperator: - // 1. the type of BoundEventAccess is the type of the event symbol. - // 2. the constant value of BoundEventAccess is always null. - // 3. the syntax of the boundEventAssignmentOperator is always AssignmentExpressionSyntax, so the syntax for the event reference would be the LHS of the assignment. - IEventSymbol @event = boundEventAssignmentOperator.Event; - Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.Event.IsStatic ? null : boundEventAssignmentOperator.ReceiverOpt)); - SyntaxNode eventAccessSyntax = ((AssignmentExpressionSyntax)syntax).Left; - - return new LazyEventReferenceExpression(@event, instance, @event, eventAccessSyntax, @event.Type, ConvertToOptional(null)); - }); - + // BoundEventAssignmentOperator doesn't hold on to BoundEventAccess provided during binding. + // Based on the implementation of those two bound node types, the following data can be retrieved w/o changing BoundEventAssignmentOperator: + // 1. the type of BoundEventAccess is the type of the event symbol. + // 2. the constant value of BoundEventAccess is always null. + // 3. the syntax of the boundEventAssignmentOperator is always AssignmentExpressionSyntax, so the syntax for the event reference would be the LHS of the assignment. + IEventSymbol @event = boundEventAssignmentOperator.Event; + Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.Event.IsStatic ? null : boundEventAssignmentOperator.ReceiverOpt)); + SyntaxNode eventAccessSyntax = ((AssignmentExpressionSyntax)syntax).Left; + + return new LazyEventReferenceExpression(@event, instance, @event, eventAccessSyntax, @event.Type, ConvertToOptional(null)); + } + + private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(BoundEventAssignmentOperator boundEventAssignmentOperator) + { + Lazy eventReference = new Lazy(() => CreateBoundEventAccessOperation(boundEventAssignmentOperator)); Lazy handlerValue = new Lazy(() => Create(boundEventAssignmentOperator.Argument)); + SyntaxNode syntax = boundEventAssignmentOperator.Syntax; bool adds = boundEventAssignmentOperator.IsAddition; ITypeSymbol type = boundEventAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundEventAssignmentOperator.ConstantValue); From 0f17f9e16fa66bce1a316423b815f597e7603063 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Wed, 2 Aug 2017 17:42:55 -0700 Subject: [PATCH 09/11] Resolve merge conflict --- .../Operations/CSharpOperationFactory.cs | 8 +-- .../Generated/Operations.xml.Generated.cs | 65 ++++--------------- .../Operations/OperationExtensions.Clone.cs | 2 +- .../VisualBasicOperationFactory_Methods.vb | 19 +----- 4 files changed, 15 insertions(+), 79 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 8b643a03dced0..b4aa8ba72aff3 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -401,7 +401,7 @@ private IEventReferenceExpression CreateBoundEventAccessOperation(BoundEventAssi Lazy instance = new Lazy(() => Create(boundEventAssignmentOperator.Event.IsStatic ? null : boundEventAssignmentOperator.ReceiverOpt)); SyntaxNode eventAccessSyntax = ((AssignmentExpressionSyntax)syntax).Left; - return new LazyEventReferenceExpression(@event, instance, @event, eventAccessSyntax, @event.Type, ConvertToOptional(null)); + return new LazyEventReferenceExpression(@event, instance, @event, _semanticModel, eventAccessSyntax, @event.Type, ConvertToOptional(null)); } private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(BoundEventAssignmentOperator boundEventAssignmentOperator) @@ -412,11 +412,7 @@ private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(B bool adds = boundEventAssignmentOperator.IsAddition; ITypeSymbol type = boundEventAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundEventAssignmentOperator.ConstantValue); -<<<<<<< HEAD - return new LazyEventAssignmentExpression(eventReference, handlerValue, adds, syntax, type, constantValue); -======= - return new LazyEventAssignmentExpression(@event, eventInstance, handlerValue, adds, _semanticModel, syntax, type, constantValue); ->>>>>>> dotnet/features/ioperation + return new LazyEventAssignmentExpression(eventReference, handlerValue, adds, _semanticModel, syntax, type, constantValue); } private IParameterReferenceExpression CreateBoundParameterOperation(BoundParameter boundParameter) diff --git a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs index 237cd8c2655b2..5e3b5c4f45a40 100644 --- a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs @@ -1368,35 +1368,21 @@ public override TResult Accept(OperationVisitor internal abstract partial class BaseEventAssignmentExpression : Operation, IEventAssignmentExpression { -<<<<<<< HEAD - protected BaseEventAssignmentExpression(bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(OperationKind.EventAssignmentExpression, syntax, type, constantValue) -======= - protected BaseEventAssignmentExpression(IEventSymbol @event, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : + protected BaseEventAssignmentExpression(bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(OperationKind.EventAssignmentExpression, semanticModel, syntax, type, constantValue) ->>>>>>> dotnet/features/ioperation { Adds = adds; } -<<<<<<< HEAD /// /// Reference to the event being bound. /// - public abstract IEventReferenceExpression EventReference { get; } + protected abstract IEventReferenceExpression EventReferenceImpl { get; } /// /// Handler supplied for the event. /// - public abstract IOperation HandlerValue { get; } -======= - /// - /// Event being bound. - /// - public IEventSymbol Event { get; } - protected abstract IOperation EventInstanceImpl { get; } protected abstract IOperation HandlerValueImpl { get; } ->>>>>>> dotnet/features/ioperation /// /// True for adding a binding, false for removing one. @@ -1414,7 +1400,7 @@ public override IEnumerable Children /// /// Instance used to refer to the event being bound. /// - public IOperation EventInstance => Operation.SetParentOperation(EventInstanceImpl, this); + public IEventReferenceExpression EventReference => Operation.SetParentOperation(EventReferenceImpl, this); /// /// Handler supplied for the event. @@ -1435,34 +1421,15 @@ public override TResult Accept(OperationVisitor internal sealed partial class EventAssignmentExpression : BaseEventAssignmentExpression, IEventAssignmentExpression { -<<<<<<< HEAD - public EventAssignmentExpression(IEventReferenceExpression eventReference, IOperation handlerValue, bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(adds, syntax, type, constantValue) + public EventAssignmentExpression(IEventReferenceExpression eventReference, IOperation handlerValue, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : + base(adds, semanticModel, syntax, type, constantValue) { - EventReference = eventReference; - HandlerValue = handlerValue; - } - - /// - /// Instance used to refer to the event being bound. - /// - public override IEventReferenceExpression EventReference { get; } - - /// - /// Handler supplied for the event. - /// - public override IOperation HandlerValue { get; } -======= - public EventAssignmentExpression(IEventSymbol @event, IOperation eventInstance, IOperation handlerValue, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(@event, adds, semanticModel, syntax, type, constantValue) - { - EventInstanceImpl = eventInstance; + EventReferenceImpl = eventReference; HandlerValueImpl = handlerValue; } - protected override IOperation EventInstanceImpl { get; } + protected override IEventReferenceExpression EventReferenceImpl { get; } protected override IOperation HandlerValueImpl { get; } ->>>>>>> dotnet/features/ioperation } /// @@ -1472,25 +1439,15 @@ internal sealed partial class LazyEventAssignmentExpression : BaseEventAssignmen { private readonly Lazy _lazyEventReference; private readonly Lazy _lazyHandlerValue; + + public LazyEventAssignmentExpression(Lazy eventReference, Lazy handlerValue, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(adds, semanticModel, syntax, type, constantValue) -<<<<<<< HEAD - public LazyEventAssignmentExpression(Lazy eventReference, Lazy handlerValue, bool adds, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(adds, syntax, type, constantValue) -======= - public LazyEventAssignmentExpression(IEventSymbol @event, Lazy eventInstance, Lazy handlerValue, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(@event, adds, semanticModel, syntax, type, constantValue) ->>>>>>> dotnet/features/ioperation { _lazyEventReference = eventReference ?? throw new System.ArgumentNullException(nameof(eventReference)); _lazyHandlerValue = handlerValue ?? throw new System.ArgumentNullException(nameof(handlerValue)); } - -<<<<<<< HEAD - /// - /// Instance used to refer to the event being bound. - /// - public override IEventReferenceExpression EventReference => _lazyEventReference.Value; -======= - protected override IOperation EventInstanceImpl => _lazyEventInstance.Value; ->>>>>>> dotnet/features/ioperation + + protected override IEventReferenceExpression EventReferenceImpl => _lazyEventReference.Value; protected override IOperation HandlerValueImpl => _lazyHandlerValue.Value; } diff --git a/src/Compilers/Core/Portable/Operations/OperationExtensions.Clone.cs b/src/Compilers/Core/Portable/Operations/OperationExtensions.Clone.cs index df8cabb04d7e7..4f825c60570f7 100644 --- a/src/Compilers/Core/Portable/Operations/OperationExtensions.Clone.cs +++ b/src/Compilers/Core/Portable/Operations/OperationExtensions.Clone.cs @@ -240,7 +240,7 @@ public override IOperation VisitEventReferenceExpression(IEventReferenceExpressi public override IOperation VisitEventAssignmentExpression(IEventAssignmentExpression operation, object argument) { - return new EventAssignmentExpression(operation.Event, Visit(operation.EventInstance), Visit(operation.HandlerValue), operation.Adds, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue); + return new EventAssignmentExpression(Visit(operation.EventReference), Visit(operation.HandlerValue), operation.Adds, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue); } public override IOperation VisitConditionalAccessExpression(IConditionalAccessExpression operation, object argument) diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb index 7ba91b4e7105e..88950fa1f0acc 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb @@ -427,27 +427,10 @@ Namespace Microsoft.CodeAnalysis.Semantics Private Function GetAddRemoveHandlerStatementExpression(statement As BoundAddRemoveHandlerStatement) As IOperation Dim eventAccess As BoundEventAccess = TryCast(statement.EventAccess, BoundEventAccess) -<<<<<<< HEAD Dim eventReference = If(eventAccess Is Nothing, Nothing, CreateBoundEventAccessOperation(eventAccess)) Dim adds = statement.Kind = BoundKind.AddHandlerStatement Return New EventAssignmentExpression( - eventReference, Create(statement.Handler), adds:=adds, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) -======= - Dim [event] As IEventSymbol = eventAccess?.EventSymbol - Dim instance = If([event] Is Nothing OrElse [event].IsStatic, Nothing, If(eventAccess IsNot Nothing, Create(eventAccess.ReceiverOpt), Nothing)) - - Return New EventAssignmentExpression( - [event], instance, Create(statement.Handler), adds:=True, semanticModel:=_semanticModel, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) - End Function - - Private Function GetRemoveStatementExpression(statement As BoundRemoveHandlerStatement) As IOperation - Dim eventAccess As BoundEventAccess = TryCast(statement.EventAccess, BoundEventAccess) - Dim [event] As IEventSymbol = eventAccess?.EventSymbol - Dim instance = If([event] Is Nothing OrElse [event].IsStatic, Nothing, If(eventAccess IsNot Nothing, Create(eventAccess.ReceiverOpt), Nothing)) - - Return New EventAssignmentExpression( - [event], instance, Create(statement.Handler), adds:=False, semanticModel:=_semanticModel, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) ->>>>>>> dotnet/features/ioperation + eventReference, Create(statement.Handler), adds:=adds, semanticModel:=_semanticModel, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing) End Function Private Shared Function GetConversionKind(kind As VisualBasic.ConversionKind) As Semantics.ConversionKind From 7c0283ccfffc95d8b965240de81503ba59af13bf Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 8 Aug 2017 11:13:03 -0700 Subject: [PATCH 10/11] Add compiler trait for IOperation tests --- .../IOperationTests_IEventAssignmentExpression.cs | 9 +++++++++ .../IOperationTests_IEventAssignmentExpression.vb | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs index dadf86ac06b64..d5f7ead28fe29 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -8,6 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public partial class IOperationTests : SemanticModelTestBase { + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void AddEventHandler() { @@ -48,6 +50,7 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void RemoveEventHandler() { @@ -84,6 +87,7 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void AddEventHandler_StaticEvent() { @@ -123,6 +127,7 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void RemoveEventHandler_StaticEvent() { @@ -162,6 +167,7 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void AddEventHandler_DelegateTypeMismatch() { @@ -205,6 +211,7 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void AddEventHandler_AssignToStaticEventOnInstance() { @@ -248,6 +255,7 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] [WorkItem(8909, "https://github.com/dotnet/roslyn/issues/8909")] public void AddEventHandler_AssignToNonStaticEventOnType() @@ -290,6 +298,7 @@ void M() VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void AddEventHandler_AssignToEventWithoutExplicitReceiver() { diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb index 6d15786445a19..009e005148703 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb @@ -1,5 +1,6 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities @@ -8,6 +9,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics Partial Public Class IOperationTests Inherits SemanticModelTestBase + Public Sub AddEventHandler() Dim source = Public Sub RemoveEventHandler() Dim source = Public Sub AddEventHandler_StaticEvent() Dim source = Public Sub RemoveEventHandler_StaticEvent() Dim source = Public Sub RemoveEventHandler_DelegateTypeMismatch() Dim source = Public Sub AddEventHandler_AssignToSharedEventOnInstance() Dim source = Public Sub AddEventHandler_AssignToNonSharedEventOnType() From 08016e47ccefbfa6aafce59bc98893261e2bbd08 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 8 Aug 2017 16:05:03 -0700 Subject: [PATCH 11/11] Fix test failure --- .../IOperationTests_IEventAssignmentExpression.cs | 6 ++++-- .../IOperationTests_IEventAssignmentExpression.vb | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs index d5f7ead28fe29..34cc6d7186d16 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.cs @@ -75,7 +75,8 @@ void M() IEventAssignmentExpression (EventRemove)) (OperationKind.EventAssignmentExpression, Type: System.Void) (Syntax: 't.MyEvent -= null') Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler) (Syntax: 't.MyEvent') Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test) (Syntax: 't') - Handler: IConversionExpression (ConversionKind.Cast, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler, Constant: null) (Syntax: 'null') + Handler: IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: System.EventHandler, Constant: null) (Syntax: 'null') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) Operand: ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: null, Constant: null) (Syntax: 'null') "; var expectedDiagnostics = new[] { @@ -196,7 +197,8 @@ void M() IEventAssignmentExpression (EventAdd)) (OperationKind.EventAssignmentExpression, Type: System.Void, IsInvalid) (Syntax: 't.MyEvent += Handler') Event Reference: IEventReferenceExpression: event System.EventHandler Test.MyEvent (OperationKind.EventReferenceExpression, Type: System.EventHandler, IsInvalid) (Syntax: 't.MyEvent') Instance Receiver: ILocalReferenceExpression: t (OperationKind.LocalReferenceExpression, Type: Test, IsInvalid) (Syntax: 't') - Handler: IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler, IsInvalid) (Syntax: 'Handler') + Handler: IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: System.EventHandler, IsInvalid) (Syntax: 'Handler') + Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IOperation: (OperationKind.None, IsInvalid) (Syntax: 'Handler') "; var expectedDiagnostics = new[] { diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb index 009e005148703..2e30be4d75413 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IEventAssignmentExpression.vb @@ -164,7 +164,8 @@ IExpressionStatement (OperationKind.ExpressionStatement, IsInvalid) (Syntax: 'Re Expression: IEventAssignmentExpression (EventRemove)) (OperationKind.EventAssignmentExpression, Type: null, IsInvalid) (Syntax: 'RemoveHandl ... AddressOf M') Event Reference: IEventReferenceExpression: Event TestClass.TestEvent As System.Action (Static) (OperationKind.EventReferenceExpression, Type: System.Action) (Syntax: 'TestEvent') Instance Receiver: null - Handler: IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: System.Action, IsInvalid) (Syntax: 'AddressOf M') + Handler: IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: System.Action, IsInvalid) (Syntax: 'AddressOf M') + Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IOperation: (OperationKind.None, IsInvalid) (Syntax: 'AddressOf M') ]]>.Value