public BuilderModellingContext(CSharpGraphBuilder owner, BuildNode node) { Contract.Requires(owner != null); Contract.Requires(node != null); this.owner = owner; this.node = node; }
public BuildNode AddNode(SyntaxNode syntax) { var nodeId = this.nodeIdProvider.GenerateNewId(); var node = new BuildNode(nodeId, syntax); this.Nodes.Add(node); Contract.Assert(nodeId.Value == this.Nodes.IndexOf(node)); return(node); }
private InnerFlowEdge TranslateEdge( BuildEdge buildEdge, BuildNode buildFrom, FlowNode flowFrom, FlowNode flowTo) { BoolHandle condition; if (buildEdge.ValueCondition?.Sort == Sort.Bool) { Contract.Assert(buildFrom.VariableModel != null); Contract.Assert(buildFrom.VariableModel is BooleanModel); var variable = (BuildVariable)buildFrom.VariableModel.AssignmentLeft.Single(); if (variable.Origin == VariableOrigin.Temporary && buildFrom.ValueModel?.AssignmentRight?.Single() is Expression valExpr && References.IsReferenceComparison( this.TranslateExpression(valExpr), out bool areEqual, out var left, out var right)) { // Reference comparison stored to a temporary variable // (as such, we suppose it is not used anywhere else) if (buildEdge.ValueCondition == ExpressionFactory.False) { condition = this.builder.AddReferenceComparison(!areEqual, left, right); } else { Contract.Assert(buildEdge.ValueCondition == ExpressionFactory.True); condition = this.builder.AddReferenceComparison(areEqual, left, right); } } else { // General boolean variable condition = (BoolHandle)this.TranslateVariable(variable); if (buildEdge.ValueCondition == ExpressionFactory.False) { condition = !condition; } else { Contract.Assert(buildEdge.ValueCondition == ExpressionFactory.True); } } }
// TODO: Substitute the temporary variables only used once in the sequence to reduce the number of assignments private void ProcessInnerNodesSequence( BuildNode buildNode, out BuildNode firstBuildNode, out BuildNode lastBuildNode, out List <Operation> operations) { operations = new List <Operation>(); var curNode = buildNode; firstBuildNode = curNode; while (true) { if (curNode.Operation == null) { var nodeAssignments = this.TranslateAssignments(curNode.VariableModel, curNode.ValueModel); operations.AddRange(nodeAssignments); } else if (curNode.Operation is HeapOperation heapOp) { var heapOps = this.TranslateHeapOperations(curNode.VariableModel, curNode.ValueModel, heapOp); operations.AddRange(heapOps); } else { Contract.Assert(curNode.Operation.Kind == SpecialOperationKind.Assertion); } if (curNode.OutgoingEdges.Count != 1) { break; } var nextNode = curNode.OutgoingEdges.Single().To; if ((nextNode.Operation is BorderOperation && nextNode.Operation.Kind != SpecialOperationKind.Assertion) || this.ingoingEdges[nextNode].Count > 1) { break; } Contract.Assert(this.ingoingEdges[nextNode].Single().From == curNode); curNode = nextNode; } lastBuildNode = curNode; }
private void MapAssignmentsToFlowNode( BuildNode firstBuildNode, BuildNode lastBuildNode, FlowNode flowNode) { int valAssignOffset = 0; int refAssignOffset = 0; int opOffset = 0; foreach (var processedNode in this.GetBuildNodesSequenceRange(firstBuildNode, lastBuildNode)) { // Note that result of the field write will be the updated reference and a new heap version bool isRefModel = processedNode.Operation?.Kind == SpecialOperationKind.FieldWrite || processedNode.VariableModel?.Factory.ValueKind == ValueModelKind.Reference; this.buildToFlowNodesMap[processedNode] = new FlowNodeMappedInfo( flowNode, isRefModel ? refAssignOffset : valAssignOffset, opOffset); if (isRefModel) { if (processedNode.VariableModel?.AssignmentLeft.Count is int count) { refAssignOffset += count; } else { Contract.Assert(processedNode.Operation.Kind == SpecialOperationKind.FieldWrite); var heapOp = (HeapOperation)processedNode.Operation; refAssignOffset += heapOp.Reference.AssignmentLeft.Count; } } else { valAssignOffset += processedNode.VariableModel?.AssignmentLeft.Count ?? 0; } opOffset++; } }
public BuildEdge(BuildNode to, Expression valueCondition = null) { this.To = to; this.ValueCondition = valueCondition; }
public BuildEdge WithTo(BuildNode to) { return(new BuildEdge(to, this.ValueCondition)); }
private FlowNode TryTranslateBorderNode(BuildNode buildNode) { var borderOp = buildNode.Operation as BorderOperation; if (borderOp == null || borderOp.Kind == SpecialOperationKind.Assertion) { return(null); } if (borderOp.Kind == SpecialOperationKind.MethodCall || borderOp.Kind == SpecialOperationKind.ExceptionThrow) { MethodLocation location; IEnumerable <Expression> flowArguments; if (borderOp.Arguments.Any(arg => arg == null)) { // We cannot model method calls without properly modelling all their arguments first location = new MethodLocation(borderOp.Method, isExplorationDisabled: true); flowArguments = Enumerable.Empty <Expression>(); } else { // TODO: Enable a configurable and extensible approach instead of this hack // Disable exploring the methods from the tool evaluation bool isExplorationDisabled = borderOp.Method.ContainingType.ToString() == "EvaluationTests.Annotations.Evaluation"; location = new MethodLocation(borderOp.Method, isExplorationDisabled); var buildArguments = borderOp.Arguments.SelectMany(typeModel => typeModel.AssignmentRight); flowArguments = buildArguments.Select(expression => this.TranslateExpression(expression)); } if (borderOp.Kind == SpecialOperationKind.MethodCall) { var returnAssignments = buildNode.VariableModel?.AssignmentLeft .Select(buildVar => this.TranslateVariable(buildVar)); // We don't allow calling base constructors, so the only way to call it is with the "new" operator // TODO: Propagate the information about constructor call other way when the above is supported var callKind = (borderOp.Method.MethodKind == MethodKind.Constructor) ? CallKind.ObjectCreation : borderOp.Method.IsStatic ? CallKind.Static : CallKind.Instance; bool isObjectCreation = (borderOp.Method.MethodKind == MethodKind.Constructor); return(this.builder.AddCallNode(location, flowArguments, returnAssignments, callKind, buildNode.Flags)); } else { Contract.Assert(borderOp.Kind == SpecialOperationKind.ExceptionThrow); return(this.builder.AddThrowExceptionNode(location, flowArguments, buildNode.Flags)); } } else { Contract.Assert(borderOp.Kind == SpecialOperationKind.Return); var returnValues = buildNode.ValueModel?.AssignmentRight .Select(expression => this.TranslateExpression(expression)) .ToImmutableArray(); if ((returnValues == null || returnValues.Value.Length == 0) && this.BuildGraph.MethodSyntax.Kind() == SyntaxKind.ConstructorDeclaration) { // A constructor returns "this" variable by convention var buildThis = this.BuildGraph.Variables.First(v => v.Origin == VariableOrigin.This); returnValues = ImmutableArray.Create((Expression)this.TranslateVariable(buildThis)); } return(this.builder.AddReturnNode(returnValues, buildNode.Flags)); } }