private void Initialize() { this.statementFlows = new List <StatementFlowView>(); this.callees = new List <MethodFlowView>(); var toolView = this.PathView.ToolView; var syntaxTree = this.location.Method.Locations[0].SourceTree; var text = syntaxTree.GetText(); ////var document = toolView.CurrentSolution.GetDocument(syntaxTree); // TODO: Consider storing this var executionModel = this.PathView.ExecutionModel; var flowGraphId = executionModel.PathNodes[this.startIndex].Graph.Id; var displayGraph = toolView.GraphProvider.GetDisplayGraph(flowGraphId); int heapVersion = this.StartHeapVersion; bool endLoop = false; for (int i = this.startIndex; i <= this.endIndex && !endLoop; i++) { heapVersion = AdvanceHeapVersion(heapVersion, executionModel, i); var flowNode = executionModel.PathNodes[i]; MethodFlowView callee = null; if (flowNode is CallFlowNode && i != this.endIndex) { // Traverse nested method calls callee = this.ProcessCallee(executionModel, i, heapVersion); if (callee.endIndex < this.endIndex) { // Nested call whose result is displayed in the subsequent flow of this method i = callee.endIndex + 1; heapVersion = callee.EndHeapVersion; Contract.Assert(flowNode == executionModel.PathNodes[i]); } else { // Nested call somewhere in which the execution ends endLoop = true; } } // Produce statements from display nodes this.ProcessStatements(text, displayGraph, executionModel, i, callee); } Contract.Assert(heapVersion <= this.EndHeapVersion); }
internal MethodFlowView( PathView pathView, MethodFlowView caller, MethodLocation location, int startIndex, int endIndex, int startHeapVersion, int endHeapVersion) { this.PathView = pathView; this.Caller = caller; this.location = location; this.startIndex = startIndex; this.endIndex = endIndex; this.StartHeapVersion = startHeapVersion; this.EndHeapVersion = endHeapVersion; }
private MethodFlowView AddCallee(int startIndex, int endIndex, int startHeapVersion, int endHeapVersion) { var toolView = this.PathView.ToolView; var graph = this.PathView.ExecutionModel.PathNodes[startIndex].Graph; var calleeLocation = toolView.GraphProvider.GetLocation(graph.Id); var callee = new MethodFlowView( this.PathView, this, calleeLocation, startIndex, endIndex, startHeapVersion, endHeapVersion); this.callees.Add(callee); return(callee); }
internal StatementFlowView( MethodFlowView methodFlowView, int index, DisplayNodeRecord displayRecord, string statement, string value, string type, HeapModelLocation?heapLocation = null, MethodFlowView calledMethod = null) { this.MethodFlowView = methodFlowView; this.Index = index; this.DisplayRecord = displayRecord; this.Statement = statement; this.Value = value; this.Type = type; this.HeapLocation = heapLocation; this.CalledMethod = calledMethod; }
private void UpdateSelectedMethod(MethodFlowView previousValue) { if (previousValue != null) { previousValue.IsSelected = false; } if (this.SelectedMethodFlow == null) { return; } // Select the appropriate method this.SelectedMethodFlow.IsSelected = true; // Expand all the methods leading to it in the chain var caller = this.SelectedMethodFlow.Caller; while (caller != null) { caller.IsExpanded = true; caller = caller.Caller; } }
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); } }