Skip to content

Commit

Permalink
IOperationsWrapperSonar: Use compiled expressions (#8105)
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-strecker-sonarsource authored Oct 19, 2023
1 parent 1624e17 commit c459f85
Show file tree
Hide file tree
Showing 12 changed files with 42 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public bool MoveNext()
return true;
}
}
Current = null;
Current = default;
return false;
}

Expand Down
42 changes: 18 additions & 24 deletions analyzers/src/SonarAnalyzer.CFG/ShimLayer/IOperationWrapperSonar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,31 @@
namespace StyleCop.Analyzers.Lightup
{
// This is a temporary substitute for IOperationWrapper in case StyleCop will accept PR https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3381
public class IOperationWrapperSonar
public readonly struct IOperationWrapperSonar
{
private static readonly PropertyInfo ParentProperty;
private static readonly PropertyInfo ChildrenProperty;
private static readonly PropertyInfo LanguageProperty;
private static readonly PropertyInfo IsImplicitProperty;
private static readonly PropertyInfo SemanticModelProperty;

private IOperation parent;
private IEnumerable<IOperation> children;
private string language;
private bool? isImplicit;
private SemanticModel semanticModel;

public IOperation Instance { get; }
public IOperation Parent => ParentProperty.ReadCached(Instance, ref parent);
public IEnumerable<IOperation> Children => ChildrenProperty.ReadCached(Instance, ref children);
public string Language => LanguageProperty.ReadCached(Instance, ref language);
public bool IsImplicit => IsImplicitProperty.ReadCached(Instance, ref isImplicit);
public SemanticModel SemanticModel => SemanticModelProperty.ReadCached(Instance, ref semanticModel);
private static readonly Func<IOperation, IOperation> ParentAccessor;
private static readonly Func<IOperation, IEnumerable<IOperation>> ChildrenAccessor;
private static readonly Func<IOperation, string> LanguageAccessor;
private static readonly Func<IOperation, bool> IsImplicitAccessor;
private static readonly Func<IOperation, SemanticModel> SemanticModelAccessor;

static IOperationWrapperSonar()
{
var type = typeof(IOperation);
ParentProperty = type.GetProperty(nameof(Parent));
ChildrenProperty = type.GetProperty(nameof(Children));
LanguageProperty = type.GetProperty(nameof(Language));
IsImplicitProperty = type.GetProperty(nameof(IsImplicit));
SemanticModelProperty = type.GetProperty(nameof(SemanticModel));
ParentAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<IOperation, IOperation>(type, nameof(Parent));
ChildrenAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<IOperation, IEnumerable<IOperation>>(type, nameof(Children));
LanguageAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<IOperation, string>(type, nameof(Language));
IsImplicitAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<IOperation, bool>(type, nameof(IsImplicit));
SemanticModelAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<IOperation, SemanticModel>(type, nameof(SemanticModel));
}

public IOperation Instance { get; }
public IOperation Parent => ParentAccessor(Instance);
public IEnumerable<IOperation> Children => ChildrenAccessor(Instance);
public string Language => LanguageAccessor(Instance);
public bool IsImplicit => IsImplicitAccessor(Instance);
public SemanticModel SemanticModel => SemanticModelAccessor(Instance);

public IOperationWrapperSonar(IOperation instance) =>
Instance = instance ?? throw new ArgumentNullException(nameof(instance));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void CheckPaths()

protected override bool IsValid(BasicBlock block)
{
if (block.OperationsAndBranchValue.ToReversedExecutionOrder().FirstOrDefault(x => context.AnalyzedSymbol.Equals(MemberSymbol(x.Instance))) is { } operation)
if (block.OperationsAndBranchValue.ToReversedExecutionOrder().FirstOrDefault(x => context.AnalyzedSymbol.Equals(MemberSymbol(x.Instance))) is { Instance: { } } operation)
{
var isWrite = operation.Parent is { Kind: OperationKindEx.SimpleAssignment } parent
&& ISimpleAssignmentOperationWrapper.FromOperation(parent).Target == operation.Instance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public sealed class ExplodedNode : IEquatable<ExplodedNode>
public ProgramState State { get; private set; }
public BasicBlock Block { get; }
public FinallyPoint FinallyPoint { get; }
public IOperationWrapperSonar Operation => index < operations.Length ? operations[index] : null;
public IOperationWrapperSonar Operation => index < operations.Length ? operations[index] : default;
public int VisitCount => State.GetVisitCount(programPointHash);

public ExplodedNode(BasicBlock block, ProgramState state, FinallyPoint finallyPoint)
Expand Down Expand Up @@ -69,7 +69,7 @@ other is not null
&& other.State.Equals(State);

public override string ToString() =>
Operation is null
? $"Block #{Block.Ordinal}, Branching{Environment.NewLine}{State}"
: $"Block #{Block.Ordinal}, Operation #{index}, {Operation.Instance.Serialize()}{Environment.NewLine}{State}";
Operation.Instance is { } operation
? $"Block #{Block.Ordinal}, Operation #{index}, {operation.Serialize()}{Environment.NewLine}{State}"
: $"Block #{Block.Ordinal}, Branching{Environment.NewLine}{State}";
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ operation is null
: SetOperationValue(operation.WrappedOperation, value);

public ProgramState SetOperationValue(IOperationWrapperSonar operation, SymbolicValue value) =>
operation is null
operation.Instance is null
? throw new ArgumentNullException(nameof(operation))
: SetOperationValue(operation.Instance, value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void Execute()
}

logger.Log(current, "Processing");
var successors = current.Operation == null ? ProcessBranching(current) : ProcessOperation(current);
var successors = current.Operation.Instance == null ? ProcessBranching(current) : ProcessOperation(current);
foreach (var node in successors)
{
logger.Log(node, "Enqueuing", true);
Expand All @@ -101,7 +101,7 @@ private bool CheckVisitCount(ExplodedNode node, int visitCount)

bool IsLoopCondition() =>
node.Block.BranchValue is not null
&& (node.Operation is null || IsInBranchValue(node.Operation.Instance))
&& (node.Operation.Instance is null || IsInBranchValue(node.Operation.Instance))
&& syntaxClassifier.IsInLoopCondition(node.Block.BranchValue.Syntax);

bool IsInBranchValue(IOperation current)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,17 @@ public void InterruptedEvaluation()
var enumerator = Compile("Method(0);", false).GetEnumerator();
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().NotBeNull();
enumerator.Current.Instance.Should().NotBeNull();

enumerator.Reset();
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().NotBeNull();
enumerator.Current.Instance.Should().NotBeNull();

enumerator.Dispose();
enumerator.MoveNext().Should().BeFalse();
enumerator.Current.Should().BeNull();
enumerator.Current.Should().NotBeNull();
enumerator.Current.Instance.Should().BeNull();
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void FromBasicBlock_Empty_HasNullOperations()
{
var cfg = TestHelper.CompileCfgBodyCS();
var sut = new ExplodedNode(cfg.EntryBlock, ProgramState.Empty, null);
sut.Operation.Should().BeNull();
sut.Operation.Instance.Should().BeNull();
}

[TestMethod]
Expand All @@ -70,7 +70,7 @@ public void IteratesExecutionOrder_CS()
TestHelper.Serialize(current.Operation).Should().Be("SimpleAssignment: value = 42 (Implicit)");

current = current.CreateNext(ProgramState.Empty);
current.Operation.Should().BeNull();
current.Operation.Instance.Should().BeNull();
}

[TestMethod]
Expand All @@ -93,7 +93,7 @@ public void IteratesExecutionOrder_VB()
TestHelper.Serialize(sut.Operation).Should().Be("SimpleAssignment: Value As Integer = 42 (Implicit)");

sut = sut.CreateNext(ProgramState.Empty);
sut.Operation.Should().BeNull();
sut.Operation.Instance.Should().BeNull();
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public void SetOperationValue_WithWrapper_NullOperation_Throws() =>

[TestMethod]
public void SetOperationValue_WithWrapperSonar_NullOperation_Throws() =>
ProgramState.Empty.Invoking(x => x.SetOperationValue((IOperationWrapperSonar)null, SymbolicValue.Empty)).Should().Throw<ArgumentNullException>();
ProgramState.Empty.Invoking(x => x.SetOperationValue((IOperationWrapperSonar)default, SymbolicValue.Empty)).Should().Throw<ArgumentNullException>();

[TestMethod]
public void SetOperationValue_OnCaptureReference_SetsValueToCapturedOperation()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void Notifications_ExecutedForAll()
{
var a = new Mock<SymbolicCheck>();
var b = new Mock<SymbolicCheck>();
var context = new SymbolicContext(null, null, ProgramState.Empty, false, 0, Array.Empty<ISymbol>());
var context = new SymbolicContext(null, default, ProgramState.Empty, false, 0, Array.Empty<ISymbol>());
a.Setup(x => x.PreProcess(context)).Returns(new[] { context.State });
a.Setup(x => x.PostProcess(context)).Returns(new[] { context.State });
var sut = new SymbolicCheckList(new[] { a.Object, b.Object });
Expand Down Expand Up @@ -71,14 +71,14 @@ public void PostProcess_CanReturnMultipleStates()
{
var triple = new PostProcessTestCheck(x => new[] { x.State, x.State, x.State });
var sut = new SymbolicCheckList(new[] { triple, triple });
sut.PostProcess(new(null, null, ProgramState.Empty, false, 0, Array.Empty<ISymbol>())).Should().HaveCount(9);
sut.PostProcess(new(null, default, ProgramState.Empty, false, 0, Array.Empty<ISymbol>())).Should().HaveCount(9);
}

[TestMethod]
public void PostProcess_CanReturnNoStates()
{
var empty = new PostProcessTestCheck(x => Array.Empty<ProgramState>());
var sut = new SymbolicCheckList(new[] { empty });
sut.PostProcess(new(null, null, ProgramState.Empty, false, 0, Array.Empty<ISymbol>())).Should().HaveCount(0);
sut.PostProcess(new(null, default, ProgramState.Empty, false, 0, Array.Empty<ISymbol>())).Should().HaveCount(0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void NullArgument_CapturedVariables_Throws()

[TestMethod]
public void NullOperation_SetsOperationToNull() =>
new SymbolicContext(null, null, ProgramState.Empty, false, 0, Array.Empty<ISymbol>()).Operation.Should().Be(null);
new SymbolicContext(null, default, ProgramState.Empty, false, 0, Array.Empty<ISymbol>()).Operation.Instance.Should().BeNull();

[TestMethod]
public void PropertiesArePersisted()
Expand Down Expand Up @@ -129,15 +129,15 @@ public void SetOperationValue_PropagatesValue()
public void WithState_SameState_ReturnsThis()
{
var state = ProgramState.Empty;
var sut = new SymbolicContext(null, null, state, false, 0, Array.Empty<ISymbol>());
var sut = new SymbolicContext(null, default, state, false, 0, Array.Empty<ISymbol>());
sut.WithState(state).Should().Be(sut);
}

[TestMethod]
public void WithState_DifferentState_ReturnsNew()
{
var state = ProgramState.Empty;
var sut = new SymbolicContext(null, null, state, false, 0, Array.Empty<ISymbol>());
var sut = new SymbolicContext(null, default, state, false, 0, Array.Empty<ISymbol>());
var newState = state.SetOperationValue(CreateOperation(), SymbolicValue.Empty);
sut.WithState(newState).Should().NotBe(sut);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static IEnumerable<MetadataReference> ProjectTypeReference(ProjectType pr

public static string Serialize(IOperationWrapperSonar operation)
{
_ = operation ?? throw new ArgumentNullException(nameof(operation));
_ = operation.Instance ?? throw new ArgumentNullException(nameof(operation));
return operation.Instance.Kind + ": " + operation.Instance.Syntax + (operation.IsImplicit ? " (Implicit)" : null);
}

Expand Down

0 comments on commit c459f85

Please sign in to comment.