Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure that EventAssignmentOperation always has a non-null EventRefer… #27046

Merged
merged 5 commits into from May 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -464,7 +464,7 @@ private IEventReferenceOperation CreateBoundEventAccessOperation(BoundEventAcces

private IEventAssignmentOperation CreateBoundEventAssignmentOperatorOperation(BoundEventAssignmentOperator boundEventAssignmentOperator)
{
Lazy<IEventReferenceOperation> eventReference = new Lazy<IEventReferenceOperation>(() => CreateBoundEventAccessOperation(boundEventAssignmentOperator));
Lazy<IOperation> eventReference = new Lazy<IOperation>(() => CreateBoundEventAccessOperation(boundEventAssignmentOperator));
Lazy<IOperation> handlerValue = new Lazy<IOperation>(() => Create(boundEventAssignmentOperator.Argument));
SyntaxNode syntax = boundEventAssignmentOperator.Syntax;
bool adds = boundEventAssignmentOperator.IsAddition;
Expand Down
Expand Up @@ -1681,7 +1681,7 @@ public override IEnumerable<IOperation> Children
/// <summary>
/// Instance used to refer to the event being bound.
/// </summary>
public abstract IEventReferenceOperation EventReference { get; }
public abstract IOperation EventReference { get; }

/// <summary>
/// Handler supplied for the event.
Expand All @@ -1702,14 +1702,14 @@ public override void Accept(OperationVisitor visitor)
/// </summary>
internal sealed partial class EventAssignmentOperation : BaseEventAssignmentOperation, IEventAssignmentOperation
{
public EventAssignmentOperation(IEventReferenceOperation eventReference, IOperation handlerValue, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
public EventAssignmentOperation(IOperation eventReference, IOperation handlerValue, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(adds, semanticModel, syntax, type, constantValue, isImplicit)
{
EventReference = SetParentOperation(eventReference, this);
HandlerValue = SetParentOperation(handlerValue, this);
}

public override IEventReferenceOperation EventReference { get; }
public override IOperation EventReference { get; }
public override IOperation HandlerValue { get; }
}

Expand All @@ -1718,17 +1718,17 @@ internal sealed partial class EventAssignmentOperation : BaseEventAssignmentOper
/// </summary>
internal sealed partial class LazyEventAssignmentOperation : BaseEventAssignmentOperation, IEventAssignmentOperation
{
private readonly Lazy<IEventReferenceOperation> _lazyEventReference;
private readonly Lazy<IOperation> _lazyEventReference;
private readonly Lazy<IOperation> _lazyHandlerValue;

public LazyEventAssignmentOperation(Lazy<IEventReferenceOperation> eventReference, Lazy<IOperation> handlerValue, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
public LazyEventAssignmentOperation(Lazy<IOperation> eventReference, Lazy<IOperation> handlerValue, bool adds, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(adds, semanticModel, syntax, type, constantValue, isImplicit)
{
_lazyEventReference = eventReference ?? throw new System.ArgumentNullException(nameof(eventReference));
_lazyHandlerValue = handlerValue ?? throw new System.ArgumentNullException(nameof(handlerValue));
}

public override IEventReferenceOperation EventReference => SetParentOperation(_lazyEventReference.Value, this);
public override IOperation EventReference => SetParentOperation(_lazyEventReference.Value, this);
public override IOperation HandlerValue => SetParentOperation(_lazyHandlerValue.Value, this);
}

Expand Down
55 changes: 48 additions & 7 deletions src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs
Expand Up @@ -5042,18 +5042,59 @@ private void VisitInitializer(IOperation rewrittenTarget, ISymbolInitializerOper

public override IOperation VisitEventAssignment(IEventAssignmentOperation operation, int? captureIdForResult)
{
var instance = operation.EventReference.Event.IsStatic ? null : operation.EventReference.Instance;
if (instance != null)
IOperation visitedEventReference, visitedHandler;

// Get the IEventReferenceOperation, digging through IParenthesizedOperation.
// Note that for error cases, the event reference might be an IInvalidOperation.
IEventReferenceOperation eventReference = getEventReference();
if (eventReference != null)
{
_evalStack.Push(Visit(instance));
// Preserve the IEventReferenceOperation.
var eventReferenceInstance = eventReference.Event.IsStatic ? null : eventReference.Instance;
if (eventReferenceInstance != null)
{
_evalStack.Push(Visit(eventReferenceInstance));
}

visitedHandler = Visit(operation.HandlerValue);

IOperation visitedInstance = eventReferenceInstance == null ? null : _evalStack.Pop();
visitedEventReference = new EventReferenceExpression(eventReference.Event, visitedInstance,
semanticModel: null, operation.EventReference.Syntax, operation.EventReference.Type, operation.EventReference.ConstantValue, IsImplicit(operation.EventReference));
}
else
{
Debug.Assert(operation.EventReference != null);
Debug.Assert(operation.EventReference.Kind == OperationKind.Invalid);

IOperation visitedHandler = Visit(operation.HandlerValue);
IOperation visitedInstance = instance == null ? null : _evalStack.Pop();
var visitedEventReference = new EventReferenceExpression(operation.EventReference.Event, visitedInstance,
semanticModel: null, operation.EventReference.Syntax, operation.EventReference.Type, operation.EventReference.ConstantValue, IsImplicit(operation.EventReference));
_evalStack.Push(Visit(operation.EventReference));
visitedHandler = Visit(operation.HandlerValue);
visitedEventReference = _evalStack.Pop();
}

return new EventAssignmentOperation(visitedEventReference, visitedHandler, operation.Adds, semanticModel: null,
operation.Syntax, operation.Type, operation.ConstantValue, IsImplicit(operation));

IEventReferenceOperation getEventReference()
{
IOperation current = operation.EventReference;

while (true)
{
switch (current.Kind)
{
case OperationKind.EventReference:
return (IEventReferenceOperation)current;

case OperationKind.Parenthesized:
current = ((IParenthesizedOperation)current).Operand;
continue;

default:
return null;
}
}
}
}

public override IOperation VisitRaiseEvent(IRaiseEventOperation operation, int? captureIdForResult)
Expand Down
Expand Up @@ -19,7 +19,7 @@ public interface IEventAssignmentOperation : IOperation
/// <summary>
/// Reference to the event being bound.
/// </summary>
IEventReferenceOperation EventReference { get; }
IOperation EventReference { get; }

/// <summary>
/// Handler supplied for the event.
Expand Down
1 change: 0 additions & 1 deletion src/Compilers/Core/Portable/PublicAPI.Shipped.txt
Expand Up @@ -1402,7 +1402,6 @@ Microsoft.CodeAnalysis.Operations.IEmptyOperation
Microsoft.CodeAnalysis.Operations.IEndOperation
Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation
Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation.Adds.get -> bool
Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation.EventReference.get -> Microsoft.CodeAnalysis.Operations.IEventReferenceOperation
Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation.HandlerValue.get -> Microsoft.CodeAnalysis.IOperation
Microsoft.CodeAnalysis.Operations.IEventReferenceOperation
Microsoft.CodeAnalysis.Operations.IEventReferenceOperation.Event.get -> Microsoft.CodeAnalysis.IEventSymbol
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/Core/Portable/PublicAPI.Unshipped.txt
@@ -1,3 +1,4 @@
*REMOVED*Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation.EventReference.get -> Microsoft.CodeAnalysis.Operations.IEventReferenceOperation
Copy link
Member Author

@mavasani mavasani May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will send an email out to the Roslyn API compat council for this change. #Resolved

Microsoft.CodeAnalysis.CompilationOptions.MetadataImportOptions.get -> Microsoft.CodeAnalysis.MetadataImportOptions
Microsoft.CodeAnalysis.CompilationOptions.WithMetadataImportOptions(Microsoft.CodeAnalysis.MetadataImportOptions value) -> Microsoft.CodeAnalysis.CompilationOptions
Microsoft.CodeAnalysis.Emit.EmitOptions.EmitOptions(bool metadataOnly = false, Microsoft.CodeAnalysis.Emit.DebugInformationFormat debugInformationFormat = (Microsoft.CodeAnalysis.Emit.DebugInformationFormat)0, string pdbFilePath = null, string outputNameOverride = null, int fileAlignment = 0, ulong baseAddress = 0, bool highEntropyVirtualAddressSpace = false, Microsoft.CodeAnalysis.SubsystemVersion subsystemVersion = default(Microsoft.CodeAnalysis.SubsystemVersion), string runtimeMetadataVersion = null, bool tolerateErrors = false, bool includePrivateMembers = true, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Emit.InstrumentationKind> instrumentationKinds = default(System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Emit.InstrumentationKind>), System.Security.Cryptography.HashAlgorithmName? pdbChecksumAlgorithm = null) -> void
Expand Down Expand Up @@ -80,6 +81,7 @@ Microsoft.CodeAnalysis.Operations.IConstructorBodyOperation.Initializer.get -> M
Microsoft.CodeAnalysis.Operations.IConstructorBodyOperation.Locals.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.ILocalSymbol>
Microsoft.CodeAnalysis.Operations.IDiscardOperation
Microsoft.CodeAnalysis.Operations.IDiscardOperation.DiscardSymbol.get -> Microsoft.CodeAnalysis.IDiscardSymbol
Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation.EventReference.get -> Microsoft.CodeAnalysis.IOperation
Microsoft.CodeAnalysis.Operations.IFlowCaptureOperation
Microsoft.CodeAnalysis.Operations.IFlowCaptureOperation.Id.get -> int
Microsoft.CodeAnalysis.Operations.IFlowCaptureOperation.Value.get -> Microsoft.CodeAnalysis.IOperation
Expand Down
13 changes: 8 additions & 5 deletions src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb
Expand Up @@ -826,9 +826,12 @@ Public MustInherit Class BasicTestBase

Protected Shared Sub VerifyFlowGraphForTest(Of TSyntaxNode As SyntaxNode)(compilation As VisualBasicCompilation, expectedFlowGraph As String, Optional which As Integer = 0)
Dim tree = compilation.SyntaxTrees(0)
Dim model = compilation.GetSemanticModel(tree)
Dim syntaxNode As SyntaxNode = CompilationUtils.FindBindingText(Of TSyntaxNode)(compilation, tree.FilePath, which, prefixMatch:=True)
VerifyFlowGraph(compilation, syntaxNode, expectedFlowGraph)
End Sub

Protected Shared Sub VerifyFlowGraph(compilation As VisualBasicCompilation, syntaxNode As SyntaxNode, expectedFlowGraph As String)
Dim model = compilation.GetSemanticModel(syntaxNode.SyntaxTree)
Dim graph As Operations.ControlFlowGraph = ControlFlowGraphVerifier.GetControlFlowGraph(syntaxNode, model)
ControlFlowGraphVerifier.VerifyGraph(compilation, expectedFlowGraph, graph)
End Sub
Expand Down Expand Up @@ -865,9 +868,9 @@ Public MustInherit Class BasicTestBase
VerifyOperationTreeForTest(Of TSyntaxNode)(compilation, fileName, expectedOperationTree, which, additionalOperationTreeVerifier)
End Sub

Friend Shared Sub VerifyFlowGraphAndDiagnosticsForTest(Of TSyntaxNode As SyntaxNode)(compilation As VisualBasicCompilation, expectedOperationTree As String, expectedDiagnostics As String, Optional which As Integer = 0)
Friend Shared Sub VerifyFlowGraphAndDiagnosticsForTest(Of TSyntaxNode As SyntaxNode)(compilation As VisualBasicCompilation, expectedFlowGraph As String, expectedDiagnostics As String, Optional which As Integer = 0)
compilation.AssertTheseDiagnostics(FilterString(expectedDiagnostics))
VerifyFlowGraphForTest(Of TSyntaxNode)(compilation, expectedOperationTree, which)
VerifyFlowGraphForTest(Of TSyntaxNode)(compilation, expectedFlowGraph, which)
End Sub

Friend Shared Sub VerifyOperationTreeAndDiagnosticsForTest(Of TSyntaxNode As SyntaxNode)(
Expand All @@ -892,7 +895,7 @@ Public MustInherit Class BasicTestBase

Friend Shared Sub VerifyFlowGraphAndDiagnosticsForTest(Of TSyntaxNode As SyntaxNode)(
testSrc As String,
expectedOperationTree As String,
expectedFlowGraph As String,
expectedDiagnostics As String,
Optional compilationOptions As VisualBasicCompilationOptions = Nothing,
Optional parseOptions As VisualBasicParseOptions = Nothing,
Expand All @@ -907,7 +910,7 @@ Public MustInherit Class BasicTestBase
Dim references = defaultRefs.Concat({ValueTupleRef, SystemRuntimeFacadeRef})
references = If(additionalReferences IsNot Nothing, references.Concat(additionalReferences), references)
Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, references:=references, options:=If(compilationOptions, TestOptions.ReleaseDll))
VerifyFlowGraphAndDiagnosticsForTest(Of TSyntaxNode)(compilation, expectedOperationTree, expectedDiagnostics, which)
VerifyFlowGraphAndDiagnosticsForTest(Of TSyntaxNode)(compilation, expectedFlowGraph, expectedDiagnostics, which)
End Sub


Expand Down
Expand Up @@ -421,11 +421,11 @@ Namespace Microsoft.CodeAnalysis.Operations
End Function

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 eventAccess As IOperation = Create(statement.EventAccess)
Dim handler As IOperation = Create(statement.Handler)
Dim adds = statement.Kind = BoundKind.AddHandlerStatement
Return New EventAssignmentOperation(
eventReference, Create(statement.Handler), adds:=adds, semanticModel:=_semanticModel, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing, isImplicit:=True)
eventAccess, handler, adds:=adds, semanticModel:=_semanticModel, syntax:=statement.Syntax, type:=Nothing, constantValue:=Nothing, isImplicit:=True)
End Function

#Region "Conversions"
Expand Down