private static ImmutableHashSet <CaptureId> CreateLValueFlowCaptures(ControlFlowGraph cfg) { var lvalueFlowCaptureIdBuilder = PooledHashSet <CaptureId> .GetInstance(); #if DEBUG var rvalueFlowCaptureIds = new Dictionary <CaptureId, HashSet <IFlowCaptureReferenceOperation> >(); #endif foreach (var flowCaptureReference in cfg.DescendantOperations <IFlowCaptureReferenceOperation>(OperationKind.FlowCaptureReference)) { if (flowCaptureReference.IsLValueFlowCaptureReference()) { lvalueFlowCaptureIdBuilder.Add(flowCaptureReference.Id); } #if DEBUG else { if (!rvalueFlowCaptureIds.TryGetValue(flowCaptureReference.Id, out var operations)) { operations = new HashSet <IFlowCaptureReferenceOperation>(); rvalueFlowCaptureIds[flowCaptureReference.Id] = operations; } operations.Add(flowCaptureReference); } #endif } #if DEBUG if (lvalueFlowCaptureIdBuilder.Count > 0) { foreach (var captureId in lvalueFlowCaptureIdBuilder) { if (rvalueFlowCaptureIds.ContainsKey(captureId)) { // Flow capture reference is used on left side as well as right side for // CFG generated for coalesce assignment operation ('??=') // Do not fire an assert for this known anomaly. var operations = rvalueFlowCaptureIds[captureId]; if (operations.Count == 1 && operations.Single().Parent?.Kind == OperationKind.FlowCapture) { continue; } Debug.Fail("Flow capture used as both an r-value and an l-value?"); } } } #endif return(lvalueFlowCaptureIdBuilder.ToImmutableAndFree()); }
private static ImmutableHashSet <CaptureId> CreateLValueFlowCaptures(ControlFlowGraph cfg) { var lvalueFlowCaptureIdBuilder = PooledHashSet <CaptureId> .GetInstance(); #if DEBUG var rvalueFlowCaptureIds = new HashSet <CaptureId>(); #endif foreach (var flowCaptureReference in cfg.DescendantOperations <IFlowCaptureReferenceOperation>(OperationKind.FlowCaptureReference)) { if (flowCaptureReference.Parent is IAssignmentOperation assignment && assignment.Target == flowCaptureReference) { lvalueFlowCaptureIdBuilder.Add(flowCaptureReference.Id); }
public static ImmutableDictionary <CaptureId, FlowCaptureKind> CreateLValueFlowCaptures(ControlFlowGraph cfg) { // This method identifies flow capture reference operations that are target of an assignment // and marks them as lvalue flow captures. // Control flow graph can also contain flow captures // that are r-value captures at some point and l-values captures at other point in // the flow graph. Specifically, for an ICoalesceOperation a flow capture acts // as both an r-value and l-value flow capture. ImmutableDictionary <CaptureId, FlowCaptureKind> .Builder lvalueFlowCaptureIdBuilder = null; var rvalueFlowCaptureIds = new HashSet <CaptureId> (); foreach (var flowCaptureReference in cfg.DescendantOperations <IFlowCaptureReferenceOperation> (OperationKind.FlowCaptureReference)) { if (flowCaptureReference.Parent is IAssignmentOperation assignment && assignment.Target == flowCaptureReference || flowCaptureReference.IsInLeftOfDeconstructionAssignment(out _)) { lvalueFlowCaptureIdBuilder ??= ImmutableDictionary.CreateBuilder <CaptureId, FlowCaptureKind> (); var captureKind = flowCaptureReference.Parent.IsAnyCompoundAssignment() || rvalueFlowCaptureIds.Contains(flowCaptureReference.Id) ? FlowCaptureKind.LValueAndRValueCapture : FlowCaptureKind.LValueCapture; lvalueFlowCaptureIdBuilder.Add(flowCaptureReference.Id, captureKind); }
public static IEnumerable <T> DescendantOperations <T> (this ControlFlowGraph cfg, OperationKind operationKind) where T : IOperation => cfg.DescendantOperations().Where(d => d?.Kind == operationKind).Cast <T> ();