Skip to content

Commit

Permalink
SE: Refactor FlowCaptureReference to operation processor (#7353)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavel-mikula-sonarsource authored Jun 9, 2023
1 parent 351706c commit 2728acd
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ internal static class OperationDispatcher
{ OperationKindEx.EventReference, new EventReference() },
{ OperationKindEx.FieldReference, new FieldReference() },
{ OperationKindEx.FlowCapture, new FlowCapture() },
{ OperationKindEx.FlowCaptureReference, new FlowCaptureReference() },
{ OperationKindEx.Increment, new IncrementOrDecrement() },
{ OperationKindEx.InstanceReference, new InstanceReference() },
{ OperationKindEx.LocalReference, new LocalReference() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,12 @@ protected override IFlowCaptureOperationWrapper Convert(IOperation operation) =>
protected override ProgramState Process(SymbolicContext context, IFlowCaptureOperationWrapper capture) =>
context.State.SetCapture(capture.Id, context.State.ResolveCapture(capture.Value)); // Capture can transitively reference another IFlowCaptureReference
}

internal sealed class FlowCaptureReference : SimpleProcessor<IFlowCaptureReferenceOperationWrapper>
{
protected override IFlowCaptureReferenceOperationWrapper Convert(IOperation operation) =>
IFlowCaptureReferenceOperationWrapper.FromOperation(operation);

protected override ProgramState Process(SymbolicContext context, IFlowCaptureReferenceOperationWrapper capture) =>
context.State.SetOperationValue(capture, context.State[context.State.ResolveCapture(capture.WrappedOperation)]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public sealed record ProgramState : IEquatable<ProgramState>
public ExceptionState Exception => Exceptions.IsEmpty ? null : Exceptions.Peek();
public SymbolicValue this[IOperationWrapperSonar operation] => this[operation.Instance];
public SymbolicValue this[IOperationWrapper operation] => this[operation.WrappedOperation];
public SymbolicValue this[IOperation operation] => OperationValue.TryGetValue(ResolveCapture(operation), out var value) ? value : null;
public SymbolicValue this[IOperation operation] => OperationValue.TryGetValue(operation, out var value) ? value : null;
public SymbolicValue this[ISymbol symbol] => SymbolValue.TryGetValue(symbol, out var value) ? value : null;
public IOperation this[CaptureId capture] => CaptureOperation.TryGetValue(capture, out var value) ? value : null;

Expand Down Expand Up @@ -74,10 +74,13 @@ operation is null
: SetOperationValue(operation.Instance, value);

public ProgramState SetOperationValue(IOperation operation, SymbolicValue value) =>
(operation ?? throw new ArgumentNullException(nameof(operation))) is var _
&& value is null
? this with { OperationValue = OperationValue.Remove(ResolveCapture(operation)) }
: this with { OperationValue = OperationValue.SetItem(ResolveCapture(operation), value) };
SetOperationValueCore(ResolveCapture(operation), value);

/// <summary>
/// Sets state directly to the FlowCaptureReferenceOperation directly, without resolving the capture itself.
/// </summary>
public ProgramState SetOperationValue(IFlowCaptureReferenceOperationWrapper capture, SymbolicValue value) =>
SetOperationValueCore(capture.WrappedOperation, value);

public ProgramState SetOperationConstraint(IOperationWrapper operation, SymbolicConstraint constraint) =>
SetOperationConstraint(operation.WrappedOperation, constraint);
Expand Down Expand Up @@ -168,6 +171,12 @@ public ProgramState[] ToArray() =>
public override string ToString() =>
Equals(Empty) ? "Empty" + Environment.NewLine : SerializeExceptions() + SerializeSymbols() + SerializeOperations() + SerializeCaptures();

private ProgramState SetOperationValueCore(IOperation operation, SymbolicValue value) =>
(operation ?? throw new ArgumentNullException(nameof(operation))) is var _
&& value is null
? this with { OperationValue = OperationValue.Remove(operation) }
: this with { OperationValue = OperationValue.SetItem(operation, value) };

private string SerializeExceptions() =>
Exceptions.IsEmpty ? null : Exceptions.JoinStr(string.Empty, x => $"Exception: {x}{Environment.NewLine}");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,21 @@ public void SetOperationValue_OnCaptureReference_SetsValueToCapturedOperation()
sut[capture.Value].Should().Be(value);
}

[TestMethod]
public void SetOperationValue_OnFlowCaptureReferenceOperationWrapper_SetsValueToOperation()
{
var value = SymbolicValue.Empty;
var cfg = TestHelper.CompileCfgBodyCS("a ??= b;", "object a, object b");
var capture = IFlowCaptureOperationWrapper.FromOperation(cfg.Blocks[1].Operations[0]);
var captureReference = IFlowCaptureReferenceOperationWrapper.FromOperation(cfg.Blocks[3].Operations[0].Children.First());
captureReference.Id.Should().Be(capture.Id);
var sut = ProgramState.Empty
.SetCapture(capture.Id, capture.Value)
.SetOperationValue(captureReference, value);
sut[capture.Value].Should().BeNull();
sut[captureReference].Should().Be(value);
}

[TestMethod]
public void ResetOperations_IsImmutable()
{
Expand Down

0 comments on commit 2728acd

Please sign in to comment.