// TODO: Do it incrementally // TODO: Heap internal void Update(StatementFlowView nextStatement) { if (nextStatement == this.nextStatement) { return; } this.Variables.Clear(); this.nextStatement = nextStatement; if (this.nextStatement == null) { this.heapVersion = 0; return; } this.heapVersion = this.nextStatement.MethodFlowView.StartHeapVersion; var varMap = new Dictionary <string, VariableReplayView>(); foreach (var statement in this.nextStatement.MethodFlowView.StatementFlows) { if (statement == this.nextStatement) { break; } if (statement.DisplayRecord.VariableName is string varName) { if (!varMap.TryGetValue(varName, out var varView)) { varView = new VariableReplayView( varName, statement.Value, statement.Type, statement.HeapLocation); varMap.Add(varName, varView); this.Variables.Add(varView); } varView.Value = statement.Value; varView.Type = statement.Type; varView.HeapLocation = statement.HeapLocation; } if (statement.HeapLocation?.HeapVersion > this.heapVersion) { this.heapVersion = statement.HeapLocation.Value.HeapVersion; } else if (statement.CalledMethod?.EndHeapVersion > this.heapVersion) { this.heapVersion = statement.CalledMethod.EndHeapVersion; } } this.heap.Redraw(); }
private void UpdateToolSelectedStatement(StatementFlowView statement) { // The last assignment will cause calling this.Update(statement) this.ToolView.SelectedPath = statement.MethodFlowView.PathView; this.ToolView.SelectedPath.SelectedMethodFlow = statement.MethodFlowView; if (this.ToolView.SelectedPath.SelectedMethodFlow.SelectedStatementFlow == statement) { // Force update this.ToolView.SelectedPath.SelectedMethodFlow.SelectedStatementFlow = null; } this.ToolView.SelectedPath.SelectedMethodFlow.SelectedStatementFlow = statement; }
private void ProcessStatements( SourceText text, DisplayGraph displayGraph, ExecutionModel executionModel, int nodeIndex, MethodFlowView calledMethod = null) { var modelManager = this.PathView.ToolView.GraphProvider.ModelManager; var flowNode = executionModel.PathNodes[nodeIndex]; bool isLastInnerNode = (nodeIndex == executionModel.PathNodes.Length - 1) && flowNode is InnerFlowNode; var nodeInterpretations = executionModel.NodeInterpretations[nodeIndex]; var heapLocations = executionModel.HeapLocations[nodeIndex]; // TODO: Consider optimizing // TODO: Group the records by their display nodes var displayRecords = new List <DisplayNodeRecord>(); foreach (var displayNode in displayGraph.Nodes) { displayRecords.AddRange(displayNode.Records.Where(record => record.FlowNode == flowNode)); // Temporary: Replace by this if only the last result of a DisplayNode is important // (Behaves weirdly in case of methods and their arguments, as they are distributed between // two FlowNodes) ////var displayRecord = displayNode.Records.LastOrDefault(record => record.FlowNode == flowNode); ////if (displayRecord != null) ////{ //// displayRecords.Add(displayRecord); ////} } foreach (var displayRecord in displayRecords) { Contract.Assert(displayRecord != null); string statement = text.ToString(displayRecord.Span); string value = null; string type = null; HeapModelLocation?heapLocation = null; if (displayRecord.Type != null) { var modelFactory = modelManager.TryGetFactory(displayRecord.Type); if (modelFactory.ValueKind == ValueModelKind.Interpretation) { // Hide the remaining portion of the inner CFG node where the exploration started from if (isLastInnerNode && displayRecord.FirstVariableIndex >= nodeInterpretations.Length) { continue; } var sortRequirements = modelFactory.GetExpressionSortRequirements(displayRecord.Type); var interpretations = nodeInterpretations .Skip(displayRecord.FirstVariableIndex) .Take(sortRequirements.Count) .ToArray(); if (interpretations.Length != 0 && interpretations.All(interpretation => interpretation != null)) { var valueModel = modelFactory.GetValueModel(displayRecord.Type, interpretations); value = valueModel.ValueText; type = displayRecord.Type.Name; } } else { Contract.Assert(modelFactory.ValueKind == ValueModelKind.Reference); bool locationExists = displayRecord.FirstVariableIndex < heapLocations.Length; // Hide the remaining portion of the inner CFG node where the exploration started from if (isLastInnerNode && !locationExists) { continue; } if (locationExists) { heapLocation = heapLocations[displayRecord.FirstVariableIndex]; var valueModel = modelFactory.GetValueModel( displayRecord.Type, heapLocation.Value, executionModel.HeapModel); value = valueModel.ValueText; type = displayRecord.Type.Name; } } } // Display a call only on the last statement of a call node // (In future, display node records concerning argument evaluation might be added) var called = (calledMethod != null && displayRecord == displayRecords.Last()) ? calledMethod : null; var statementFlow = new StatementFlowView( this, this.statementFlows.Count, displayRecord, !string.IsNullOrEmpty(statement) ? statement : displayRecord.VariableName, value, type, heapLocation, called); this.statementFlows.Add(statementFlow); } }