public void AnyVariableExpressionShouldMatch() { var variable = new DummyVariable("variable"); var pattern = ExpressionPattern.Variable <DummyInstruction>(); Assert.True(pattern.Matches(new VariableExpression <DummyInstruction>(variable))); }
public void ReplacingSourcesInPhiStatement() { var target = new DummyVariable("target"); var sources1 = new[] { new DummyVariable("source1"), new DummyVariable("source2"), new DummyVariable("source3"), new DummyVariable("source4") }; var sources2 = new[] { new DummyVariable("newSource1"), new DummyVariable("newSource2"), new DummyVariable("newSource3"), new DummyVariable("newSource4"), new DummyVariable("newSource5") }; var phi = new PhiStatement <DummyInstruction>( target, sources1.Select(s => new VariableExpression <DummyInstruction>(s))); var sourceExpr = sources2.Select(s => new VariableExpression <DummyInstruction>(s)).ToList(); phi.WithSources(sourceExpr); Assert.Equal(5, phi.Sources.Count); Assert.All(phi.Sources, s => { Assert.Equal(phi, s.Parent); Assert.Equal(sources2[sourceExpr.IndexOf(s)], s.Variable); }); }
public void IgnoreStackDependenciesWhenNotIncluded() { var variable = new DummyVariable("v1"); var dfg = new DataFlowGraph <int>(IntArchitecture.Instance); var n1 = dfg.Nodes.Add(1, 1); var n2 = dfg.Nodes.Add(2, 2); var n3 = dfg.Nodes.Add(3, 3); var n4 = dfg.Nodes.Add(4, 4); var n5 = dfg.Nodes.Add(5, 5); n1.StackDependencies.SetCount(1); n1.StackDependencies[0].Add(n2); var dependency = new VariableDependency <int>(variable); n1.VariableDependencies.Add(dependency); dependency.Add(n3); n3.StackDependencies.SetCount(1); n3.StackDependencies[0].Add(n4); dependency = new VariableDependency <int>(variable); n3.VariableDependencies.Add(dependency); dependency.Add(n5); Assert.Equal(new[] { n5, n3, n1 }, n1.GetOrderedDependencies(DependencyCollectionFlags.IncludeVariableDependencies)); }
private string AddLocalVariable(DummyVariable incrementor, Type type) { string localName = incrementor.GetNext(); _currentOperand = _g.Local(type); _localVariablesTable.Add(localName, _currentOperand); return(localName); }
public void JoiningControlFlowPathsWithDifferentVariableVersionsShouldResultInPhiNode() { var variable = new DummyVariable("temp"); var cfg = ConstructAst(new[] { DummyInstruction.Push(0, 1), DummyInstruction.JmpCond(1, 5), DummyInstruction.Push(2, 1), DummyInstruction.Set(3, variable), DummyInstruction.Jmp(4, 7), DummyInstruction.Push(5, 1), DummyInstruction.Set(6, variable), DummyInstruction.Get(7, variable), DummyInstruction.Pop(8, 1), DummyInstruction.Ret(9) }); var phiSourcesCapture = new CaptureGroup("sources"); var variablesCapture = new CaptureGroup("variables"); // temp_vx = set(?) var assignPattern = StatementPattern .Assignment <DummyInstruction>() .WithExpression(ExpressionPattern .Instruction(new DummyInstructionPattern(DummyOpCode.Set)) .WithArguments(1)) .CaptureVariables(variablesCapture); // variable = phi(?, ?) var phiPattern = StatementPattern .Phi <DummyInstruction>() .WithSources(2) .CaptureSources(phiSourcesCapture); var set1Result = assignPattern.FindFirstMatch(cfg.Nodes[2].Contents.Instructions); var set2Result = assignPattern.FindFirstMatch(cfg.Nodes[5].Contents.Instructions); var phiResult = phiPattern.Match(cfg.Nodes[7].Contents.Header); Assert.True(set1Result.IsSuccess, "Node 2 was expected to contain an assignment statement."); Assert.True(set2Result.IsSuccess, "Node 5 was expected to contain an assignment statement."); Assert.True(phiResult.IsSuccess, "Node 7 was expected to start with a phi statement."); var sources = phiResult.Captures[phiSourcesCapture] .Cast <VariableExpression <DummyInstruction> >() .Select(s => s.Variable); var allVariables = new[] { (IVariable)set1Result.Captures[variablesCapture][0], (IVariable)set2Result.Captures[variablesCapture][0] }; Assert.Equal(allVariables.ToHashSet(), sources.ToHashSet()); }
public void ReplacingVariableInVariableExpression() { var var1 = new DummyVariable("old"); var var2 = new DummyVariable("new"); var expr = new VariableExpression <DummyInstruction>(var1); Assert.Equal(var2, expr.WithVariable(var2).Variable); }
public void DifferentSpecificVariableShouldMatch() { var variable1 = new DummyVariable("variable1"); var variable2 = new DummyVariable("variable2"); var pattern = ExpressionPattern.Variable <DummyInstruction>(variable1); Assert.False(pattern.Matches(new VariableExpression <DummyInstruction>(variable2))); }
public void AddVariableDependencyWithMultipleSourcesShouldSetDegree() { var variable = new DummyVariable("var1"); var graph = new DataFlowGraph <int>(IntArchitecture.Instance); var n1 = graph.Nodes.Add(1, 1); var n2 = graph.Nodes.Add(2, 2); var n3 = graph.Nodes.Add(3, 3); Assert.Equal(0, n1.OutDegree); n1.VariableDependencies.Add(variable, new DataDependency <int>(new[] { n2, n3 })); Assert.Equal(2, n1.OutDegree); }
public void AddVariableDependencyWithSingeSourceShouldSetDegree() { var variable = new DummyVariable("var1"); var graph = new DataFlowGraph <int>(IntArchitecture.Instance); var n1 = graph.Nodes.Add(1, 1); var n2 = graph.Nodes.Add(2, 2); Assert.Equal(0, n1.OutDegree); n1.VariableDependencies.Add(variable, new DataDependency <int>(n2)); Assert.Equal(1, n1.OutDegree); Assert.Equal(1, n2.InDegree); }
public void VariableAccessThatHasntBeenWrittenToBeforeShouldntResultInPhi() { var variable = new DummyVariable("dummy"); var cfg = ConstructAst(new[] { DummyInstruction.Get(0, variable), DummyInstruction.Op(1, 1, 0), DummyInstruction.Ret(2) }); Assert.Single(cfg.Nodes); Assert.All(cfg.Entrypoint.Contents.Instructions, Assert.IsNotType <PhiStatement <DummyInstruction> >); }
public void ReplacingTargetVariableInPhiStatement() { var target1 = new DummyVariable("old"); var target2 = new DummyVariable("new"); var sources = new[] { new DummyVariable("source1"), new DummyVariable("source2"), new DummyVariable("source3"), new DummyVariable("source4") }; var phi = new PhiStatement <DummyInstruction>( target1, sources.Select(s => new VariableExpression <DummyInstruction>(s))); Assert.Equal(target2, phi.WithTarget(target2).Target); }
public void DisconnectNodeShouldRemoveEdge(DataDependencyType edgeType, bool removeSourceNode) { var variable = new DummyVariable("var"); var graph = new DataFlowGraph <int>(IntArchitecture.Instance); var n1 = new DataFlowNode <int>(0, 0); n1.StackDependencies.Add(new DataDependency <int>()); n1.VariableDependencies.Add(variable, new DataDependency <int>()); var n2 = new DataFlowNode <int>(1, 1); graph.Nodes.AddRange(new[] { n1, n2 }); switch (edgeType) { case DataDependencyType.Stack: n1.StackDependencies[0].Add(new DataSource <int>(n2)); break; case DataDependencyType.Variable: n1.VariableDependencies[variable].Add(new DataSource <int>(n2)); break; default: throw new ArgumentOutOfRangeException(nameof(edgeType), edgeType, null); } if (removeSourceNode) { n1.Disconnect(); } else { n2.Disconnect(); } Assert.Empty(n1.StackDependencies[0]); Assert.Empty(n1.VariableDependencies[variable]); Assert.Empty(n2.GetDependants()); }
public void RemoveNodeShouldRemoveVarDeps() { var variable = new DummyVariable("V_1"); var dfg = new DataFlowGraph <int>(IntArchitecture.Instance); var n1 = dfg.Nodes.Add(1, 0); var n2 = dfg.Nodes.Add(2, 0); n1.VariableDependencies[variable] = new DataDependency <int>(n2); Assert.Single(n1.VariableDependencies[variable]); Assert.Single(n2.GetDependants()); dfg.Nodes.Remove(n2); Assert.Empty(n1.VariableDependencies[variable]); Assert.Empty(n2.GetDependants()); }
public void SwitchWithAssignmentsToSameVariableShouldResultInPhiNodeWithTheSameNumberOfSources() { var variable = new DummyVariable("temp"); var cfg = ConstructAst(new[] { // switch(some_value) DummyInstruction.Push(0, 1), DummyInstruction.Switch(1, 5, 8, 11), // default: DummyInstruction.Push(2, 1), DummyInstruction.Set(3, variable), DummyInstruction.Jmp(4, 13), // case 0: DummyInstruction.Push(5, 1), DummyInstruction.Set(6, variable), DummyInstruction.Jmp(7, 13), // case 1: DummyInstruction.Push(8, 1), DummyInstruction.Set(9, variable), DummyInstruction.Jmp(10, 13), // case 2: DummyInstruction.Push(11, 1), DummyInstruction.Set(12, variable), // end: DummyInstruction.Get(13, variable), DummyInstruction.Pop(14, 1), DummyInstruction.Ret(15) }); // variable = phi(?, ?) var phiPattern = StatementPattern .Phi <DummyInstruction>() .WithSources(4); Assert.True(phiPattern.Matches(cfg.Nodes[13].Contents.Header), "Node 13 was expected to start with a phi node with 4 sources."); }
public void MergeSingleVariableNoChange() { var source = CreateDummyNode(0); var variable = new DummyVariable("V_1"); var variables1 = ImmutableDictionary <IVariable, SymbolicValue <DummyInstruction> > .Empty; variables1 = variables1.SetItem(variable, SymbolicValue <DummyInstruction> .CreateVariableValue(source, variable)); var variables2 = ImmutableDictionary <IVariable, SymbolicValue <DummyInstruction> > .Empty; variables2 = variables2.SetItem(variable, SymbolicValue <DummyInstruction> .CreateVariableValue(source, variable)); var state1 = new SymbolicProgramState <DummyInstruction>(0, variables1); var state2 = new SymbolicProgramState <DummyInstruction>(0, variables2); Assert.False(state1.MergeStates(state2, out var newState)); Assert.Equal(new HashSet <DataFlowNode <DummyInstruction> >(new [] { source }), newState.Variables[variable].GetNodes()); }
public void IgnoreVariableDependenciesWhenNotIncluded() { var variable = new DummyVariable("v1"); var dfg = new DataFlowGraph <int>(IntArchitecture.Instance); var n1 = dfg.Nodes.Add(1, 1); var n2 = dfg.Nodes.Add(2, 2); var n3 = dfg.Nodes.Add(3, 3); var n4 = dfg.Nodes.Add(4, 4); var n5 = dfg.Nodes.Add(5, 5); n1.StackDependencies.Add(new DataDependency <int>(n2)); n1.VariableDependencies.Add(variable, new DataDependency <int>(n3)); n2.StackDependencies.Add(new DataDependency <int>(n4)); n2.VariableDependencies.Add(variable, new DataDependency <int>(n5)); Assert.Equal(new[] { n4, n2, n1 }, n1.GetOrderedDependencies(DependencyCollectionFlags.IncludeStackDependencies)); }
public void LoopCounterShouldResultInOnlyOnePhiNode() { var counterVariable = new DummyVariable("i"); var cfg = ConstructAst(new[] { // i = initial(); DummyInstruction.Push(0, 1), DummyInstruction.Set(1, counterVariable), // loop: // if (cond(i)) goto end; DummyInstruction.Get(2, counterVariable), DummyInstruction.JmpCond(3, 9), // Loop body. DummyInstruction.Op(4, 0, 0), // i = next(i); // goto loop DummyInstruction.Get(5, counterVariable), DummyInstruction.Op(6, 1, 1), DummyInstruction.Set(7, counterVariable), DummyInstruction.Jmp(8, 2), // end: DummyInstruction.Ret(9) }); // variable = phi(?, ?) var phiPattern = StatementPattern .Phi <DummyInstruction>() .WithSources(2); Assert.True(phiPattern.Matches(cfg.Nodes[2].Contents.Header)); Assert.All(cfg.Nodes[0].Contents.Instructions, s => Assert.False(phiPattern.Matches(s))); Assert.All(cfg.Nodes[4].Contents.Instructions, s => Assert.False(phiPattern.Matches(s))); Assert.All(cfg.Nodes[9].Contents.Instructions, s => Assert.False(phiPattern.Matches(s))); }
public void ReplacingExpressionInAssignmentShouldChangeParent() { var var1 = new DummyVariable("1"); var ast = ConstructAst(new[] { DummyInstruction.Push(0, 1), DummyInstruction.Set(1, var1), DummyInstruction.Ret(2) }); Assert.Single(ast.Nodes); var block = ast.Entrypoint.Contents.Instructions; Assert.Equal(3, block.Count); Assert.All(block, node => Assert.Null(node.Parent)); var expr = new InstructionExpression <DummyInstruction>(DummyInstruction.Jmp(0, 69), Array.Empty <Expression <DummyInstruction> >()); var asmt = Assert.IsType <AssignmentStatement <DummyInstruction> >(block[1]); Assert.Equal(expr, asmt.WithExpression(expr).Expression); Assert.Equal(asmt, expr.Parent); }
public void ReplacingVariablesInAssignmentShouldGetRidOfOldOnes() { var var1 = new DummyVariable("1"); var ast = ConstructAst(new[] { DummyInstruction.Push(0, 1), DummyInstruction.Set(1, var1), DummyInstruction.Ret(2), }); Assert.Single(ast.Nodes); var block = ast.Entrypoint.Contents.Instructions; Assert.Equal(3, block.Count); Assert.All(block, node => Assert.Null(node.Parent)); var var2 = new DummyVariable("2"); var var3 = new DummyVariable("3"); var asmt = Assert.IsType <AssignmentStatement <DummyInstruction> >(block[1]); Assert.Equal(2, asmt.WithVariables(var2, var3).Variables.Count); Assert.Equal(asmt.Variables[0], var2); Assert.Equal(asmt.Variables[1], var3); }
private static List <ExpressionBase> ConvertRoslynExpressionToWandaExpression( SimpleCompoundStatement wandaBlock, ExpressionSyntax expressionSyntax) { var result = new List <ExpressionBase>(); switch (expressionSyntax) { case AssignmentExpressionSyntax assignmentExpressionSyntax: { var left = assignmentExpressionSyntax.Left; var operatorToken = assignmentExpressionSyntax.OperatorToken; var right = assignmentExpressionSyntax.Right; var leftValue = wandaBlock.ResolveLValue(result, left, true); var rightValue = wandaBlock.ResolveValue(result, right, true); AssignmentBase assignment = null; switch (operatorToken.Kind()) { case SyntaxKind.EqualsToken: assignment = new SimpleAssignment(leftValue, rightValue); break; case SyntaxKind.SlashEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryDivideOperator.Instance); break; case SyntaxKind.PlusEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryAddOperator.Instance); break; case SyntaxKind.MinusEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinarySubtractOperator.Instance); break; case SyntaxKind.AsteriskEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryMultiplyOperator.Instance); break; case SyntaxKind.PercentEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryRemainderOperator.Instance); break; case SyntaxKind.AmpersandEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryBitAndOperator.Instance); break; case SyntaxKind.CaretEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryBitXorOperator.Instance); break; case SyntaxKind.BarEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryBitOrOperator.Instance); break; case SyntaxKind.LessThanLessThanEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryBitShiftLeftOperator.Instance); break; case SyntaxKind.GreaterThanGreaterThanEqualsToken: assignment = new OperatorAssignment(leftValue, rightValue, BinaryBitShiftRightOperator.Instance); break; case SyntaxKind.QuestionQuestionEqualsToken: break; default: throw new ArgumentOutOfRangeException(); } if (assignment != null) { result.Add(assignment); } else { Log.Debug("{Left} {Operator} {Right}", left, operatorToken.Text, right); } break; } case PrefixUnaryExpressionSyntax unaryExpressionSyntax: { var operand = unaryExpressionSyntax.Operand; var leftValue = wandaBlock.ResolveLValue(result, operand, true); AssignmentBase assignment = null; var operatorToken = unaryExpressionSyntax.OperatorToken; switch (operatorToken.Kind()) { case SyntaxKind.PlusToken: case SyntaxKind.MinusToken: case SyntaxKind.TildeToken: case SyntaxKind.ExclamationToken: break; case SyntaxKind.PlusPlusToken: assignment = new OperatorAssignment(leftValue, IntegerLiteral.One, BinaryAddOperator.Instance); break; case SyntaxKind.MinusMinusToken: assignment = new OperatorAssignment(leftValue, IntegerLiteral.One, BinarySubtractOperator.Instance); break; case SyntaxKind.AmpersandToken: case SyntaxKind.AsteriskToken: case SyntaxKind.CaretToken: break; default: throw new ArgumentOutOfRangeException(); } if (assignment != null) { result.Add(assignment); } else { Log.Debug("{Operator} {Right}", operatorToken.Text, unaryExpressionSyntax.Operand); } break; } case PostfixUnaryExpressionSyntax unaryExpressionSyntax: { var operand = unaryExpressionSyntax.Operand; var leftValue = wandaBlock.ResolveLValue(result, operand, true); AssignmentBase assignment = null; var operatorToken = unaryExpressionSyntax.OperatorToken; switch (operatorToken.Kind()) { case SyntaxKind.PlusPlusToken: assignment = new OperatorAssignment(leftValue, IntegerLiteral.One, BinaryAddOperator.Instance); break; case SyntaxKind.MinusMinusToken: assignment = new OperatorAssignment(leftValue, IntegerLiteral.One, BinarySubtractOperator.Instance); break; case SyntaxKind.ExclamationToken: break; default: throw new ArgumentOutOfRangeException(); } if (assignment != null) { // todo: that's not right. The value returned by expression is not as simple result.Add(assignment); } else { Log.Debug("{Left} {Operator}", unaryExpressionSyntax.Operand, operatorToken.Text); } break; } case InvocationExpressionSyntax invocationExpressionSyntax: { var what = invocationExpressionSyntax.Expression.ToString(); FunctionCallParameter Selector(ArgumentSyntax x) { var xRefKindKeyword = x.RefKindKeyword.Kind(); var(isRef, isOut) = ( xRefKindKeyword == SyntaxKind.RefKeyword, xRefKindKeyword == SyntaxKind.OutKeyword); return(new FunctionCallParameter { Value = wandaBlock.ResolveValue(result, x.Expression, true), Out = isOut, Ref = isRef }); } var with = invocationExpressionSyntax.ArgumentList.Arguments.Select(Selector); var functionCallOperator = new FunctionCallOperator { Name = what }; functionCallOperator.Arguments.AddRange(with); result.Add(functionCallOperator); break; } case IdentifierNameSyntax identifierNameSyntax: { result.Add(wandaBlock.ResolveVariableByName(identifierNameSyntax.Identifier.Text)); break; } case LiteralExpressionSyntax literalExpressionSyntax: { result.Add(ResolveLiteral(literalExpressionSyntax)); break; } case ElementAccessExpressionSyntax elementAccessExpressionSyntax: { result.Add( ResolveRoslynElementAccessExpressionToWandaOperator(elementAccessExpressionSyntax, result, wandaBlock)); break; } case BinaryExpressionSyntax binaryExpressionSyntax: { var operatorToken = binaryExpressionSyntax.OperatorToken; PureBase operatorBase = null; LogicBase logicBase = null; switch (operatorToken.Kind()) { case SyntaxKind.PlusToken: operatorBase = BinaryAddOperator.Instance; break; case SyntaxKind.MinusToken: operatorBase = BinarySubtractOperator.Instance; break; case SyntaxKind.AsteriskToken: operatorBase = BinaryMultiplyOperator.Instance; break; case SyntaxKind.SlashToken: operatorBase = BinaryDivideOperator.Instance; break; case SyntaxKind.PercentToken: operatorBase = BinaryRemainderOperator.Instance; break; case SyntaxKind.LessThanLessThanToken: operatorBase = BinaryBitShiftLeftOperator.Instance; break; case SyntaxKind.GreaterThanGreaterThanToken: operatorBase = BinaryBitShiftRightOperator.Instance; break; case SyntaxKind.BarBarToken: logicBase = OrLogic.Instance; break; case SyntaxKind.AmpersandAmpersandToken: logicBase = AndLogic.Instance; break; case SyntaxKind.BarToken: operatorBase = BinaryBitOrOperator.Instance; break; case SyntaxKind.AmpersandToken: operatorBase = BinaryBitAndOperator.Instance; break; case SyntaxKind.CaretToken: operatorBase = BinaryBitXorOperator.Instance; break; case SyntaxKind.EqualsEqualsToken: logicBase = EqualLogic.Instance; break; case SyntaxKind.ExclamationEqualsToken: logicBase = NotEqualLogic.Instance; break; case SyntaxKind.LessThanToken: logicBase = LessLogic.Instance; break; case SyntaxKind.LessThanEqualsToken: logicBase = LessOrEqualLogic.Instance; break; case SyntaxKind.GreaterThanToken: logicBase = GreaterLogic.Instance; break; case SyntaxKind.GreaterThanEqualsToken: logicBase = GreaterOrEqualLogic.Instance; break; case SyntaxKind.IsKeyword: case SyntaxKind.AsKeyword: case SyntaxKind.QuestionQuestionToken: break; default: throw new ArgumentOutOfRangeException(); } switch (operatorBase != null, logicBase != null) { case (true, false): { var left = wandaBlock.ResolveValue(result, binaryExpressionSyntax.Left, true); var right = wandaBlock.ResolveValue(result, binaryExpressionSyntax.Right, true); var dummy = new DummyVariable { TypeRef = ApproximateResultTypeOfBinaryOperator(left, right) }; wandaBlock.LocalVariables.Add(dummy); var assignment = new SimpleAssignment(dummy, left); result.Add(assignment); var operatorAssignment = new OperatorAssignment(dummy, right, operatorBase); result.Add(operatorAssignment); break; } case (false, true): { var left = wandaBlock.ResolveValue(result, binaryExpressionSyntax.Left, true); var right = wandaBlock.ResolveValue(result, binaryExpressionSyntax.Right, true); var operatorAssignment = new BinaryLogicExpression(logicBase, left, right); result.Add(operatorAssignment); break; } case (false, false): { Log.Debug("BINARY: {Left} {Operator} {Right} ({Kind})", binaryExpressionSyntax.Left, operatorToken.Text, binaryExpressionSyntax.Right, operatorToken.Kind()); break; } default: throw new ArgumentOutOfRangeException(); } break; }
public void JoiningPathsWithMultipleAssignmentsShouldOnlyUseLatestVersion() { var variable = new DummyVariable("temp"); var cfg = ConstructAst(new[] { // if (cond) goto else: DummyInstruction.Push(0, 1), DummyInstruction.JmpCond(1, 7), // temp = some_value (not used). DummyInstruction.Push(2, 1), DummyInstruction.Set(3, variable), // temp = some_value (render previous value useless) DummyInstruction.Push(4, 1), DummyInstruction.Set(5, variable), // goto end DummyInstruction.Jmp(6, 9), // else: // temp = some_value DummyInstruction.Push(7, 1), DummyInstruction.Set(8, variable), // end: // pop(temp) DummyInstruction.Get(9, variable), DummyInstruction.Pop(10, 1), // return DummyInstruction.Ret(11) }); var phiSourcesCapture = new CaptureGroup("sources"); var variablesCapture = new CaptureGroup("variables"); // variable = phi(?, ?) var phiPattern = StatementPattern .Phi <DummyInstruction>() .WithSources(2) .CaptureSources(phiSourcesCapture); // temp_vx = set(?) var assignPattern = StatementPattern .Assignment <DummyInstruction>() .WithExpression(ExpressionPattern .Instruction(new DummyInstructionPattern(DummyOpCode.Set)) .WithArguments(1)) .CaptureVariables(variablesCapture); var assignment1Results = assignPattern .FindAllMatches(cfg.Nodes[7].Contents.Instructions) .ToArray(); var assignment2Results = assignPattern .FindAllMatches(cfg.Nodes[2].Contents.Instructions) .ToArray(); var phiResult = phiPattern.Match(cfg.Nodes[9].Contents.Header); Assert.True(assignment1Results.Length == 1, "Node 7 was expected to have one assignment to 'temp'."); Assert.True(assignment2Results.Length == 2, "Node 2 was expected to have two assignments to 'temp'."); Assert.True(phiResult.IsSuccess, "Node 9 was expected to start with a phi node with two sources."); var sources = phiResult.Captures[phiSourcesCapture] .Cast <VariableExpression <DummyInstruction> >() .Select(s => s.Variable); var allVariables = new[] { (IVariable)assignment1Results[0].Captures[variablesCapture][0], (IVariable)assignment2Results[1].Captures[variablesCapture][0] }; Assert.Equal(allVariables.ToHashSet(), sources.ToHashSet()); }