/// <summary> /// Visits the state transition graph to find and return /// the node for the given summary. /// </summary> /// <param name="summary">MethodSummary</param> /// <param name="visited">Already visited nodes</param> /// <returns>StateTransitionGraphNode</returns> private StateTransitionGraphNode GetGraphNodeForSummary(MethodSummary summary, HashSet <StateTransitionGraphNode> visited) { visited.Add(this); StateTransitionGraphNode stateNode = null; if ((this.OnEntry != null && this.OnEntry.Equals(summary)) || (this.OnExit != null && this.OnExit.Equals(summary)) || this.Actions.Any(v => v.Equals(summary))) { stateNode = this; } else { foreach (var successor in this.ISuccessors.Where(v => !visited.Contains(v))) { var node = successor.GetGraphNodeForSummary(summary, visited); if (node != null) { stateNode = node; break; } } } return(stateNode); }
/// <summary> /// Constructs the node using information from the given state transitions /// and action bindings. /// </summary> /// <param name="stateTransitions">State transitions</param> /// <param name="actionBindings">Action bindings</param> /// <param name="visited">Already visited nodes</param> private void Construct(Dictionary <ClassDeclarationSyntax, HashSet <ClassDeclarationSyntax> > stateTransitions, Dictionary <ClassDeclarationSyntax, HashSet <MethodDeclarationSyntax> > actionBindings, HashSet <StateTransitionGraphNode> visited) { visited.Add(this); foreach (var method in this.State.ChildNodes().OfType <MethodDeclarationSyntax>()) { var summary = MethodSummary.Factory.Summarize(method); if (method.Modifiers.Any(SyntaxKind.OverrideKeyword) && method.Identifier.ValueText.Equals("OnEntry")) { this.OnEntry = summary; } else if (method.Modifiers.Any(SyntaxKind.OverrideKeyword) && method.Identifier.ValueText.Equals("OnExit")) { this.OnExit = summary; } } var actions = new HashSet <MethodDeclarationSyntax>(); if (actionBindings.ContainsKey(this.State)) { actions = actionBindings[this.State]; } foreach (var action in actions) { var actionSummary = MethodSummary.Factory.Summarize(action); this.Actions.Add(actionSummary); } var transitions = new HashSet <ClassDeclarationSyntax>(); if (stateTransitions.ContainsKey(this.State)) { transitions = stateTransitions[this.State]; } foreach (var successorState in transitions) { var successor = visited.FirstOrDefault(v => v.State.Equals(successorState)); if (successor != null) { this.ISuccessors.Add(successor); successor.IPredecessors.Add(this); } else { successor = new StateTransitionGraphNode(successorState, this.Machine); this.ISuccessors.Add(successor); successor.IPredecessors.Add(this); successor.Construct(stateTransitions, actionBindings, visited); } } }
/// <summary> /// Query checking if the field is accessed before being reset /// in the given state transition node. /// </summary> /// <param name="node">StateTransitionGraphNode</param> /// <param name="input">Input</param> /// <param name="isFirstVisit">True if first node to visit</param> /// <returns>Boolean value</returns> private static bool IsAccessedBeforeBeingReset(StateTransitionGraphNode node, object input, bool isFirstVisit) { var summary = ((Tuple <MethodSummary, ISymbol>)input).Item1; var fieldSymbol = ((Tuple <MethodSummary, ISymbol>)input).Item2; var result = false; if (isFirstVisit && node.OnExit != null && !summary.Equals(node.OnExit)) { foreach (var action in node.Actions) { result = action.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); if (result) { break; } } if (!result && node.OnExit != null) { result = node.OnExit.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); } } else if (!isFirstVisit) { if (node.OnEntry != null) { result = node.OnEntry.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); } if (!result) { foreach (var action in node.Actions) { result = action.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); if (result) { break; } } } if (!result && node.OnExit != null) { result = node.OnExit.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); } } return(result); }
/// <summary> /// Query checking if the field is accessed before being reset /// in the given state transition node. /// </summary> /// <param name="node">StateTransitionGraphNode</param> /// <param name="input">Input</param> /// <param name="isFirstVisit">True if first node to visit</param> /// <returns>Boolean value</returns> private static bool IsAccessedBeforeBeingReset(StateTransitionGraphNode node, object input, bool isFirstVisit) { var summary = ((Tuple<MethodSummary, ISymbol>)input).Item1; var fieldSymbol = ((Tuple<MethodSummary, ISymbol>)input).Item2; var result = false; if (isFirstVisit && node.OnExit != null && !summary.Equals(node.OnExit)) { foreach (var action in node.Actions) { result = action.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); if (result) { break; } } if (!result && node.OnExit != null) { result = node.OnExit.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); } } else if (!isFirstVisit) { if (node.OnEntry != null) { result = node.OnEntry.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); } if (!result) { foreach (var action in node.Actions) { result = action.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); if (result) { break; } } } if (!result && node.OnExit != null) { result = node.OnExit.FieldAccessSet.ContainsKey(fieldSymbol as IFieldSymbol); } } return result; }
/// <summary> /// Tries to construct the state transition graph for the given machine. /// </summary> /// <param name="machine">Machine</param> private static void ConstructGraphForMachine(ClassDeclarationSyntax machine) { var model = AnalysisContext.Compilation.GetSemanticModel(machine.SyntaxTree); Dictionary <ClassDeclarationSyntax, HashSet <ClassDeclarationSyntax> > stateTransitions = null; StateTransitionAnalysis.TryParseStateTransitions(out stateTransitions, machine, model); Dictionary <ClassDeclarationSyntax, HashSet <MethodDeclarationSyntax> > actionBindings = null; StateTransitionAnalysis.TryParseActionBindings(out actionBindings, machine, model); StateTransitionAnalysis.ComputeStatistics(stateTransitions, actionBindings); ClassDeclarationSyntax initState = null; foreach (var state in stateTransitions) { foreach (var attributeList in state.Key.AttributeLists) { foreach (var attribute in attributeList.Attributes) { if (attribute.Name.ToString().Equals("Microsoft.PSharp.Start")) { initState = state.Key; } } } } if (initState == null) { return; } var initNode = new StateTransitionGraphNode(initState, machine); initNode.IsStartNode = true; initNode.Construct(stateTransitions, actionBindings); AnalysisContext.StateTransitionGraphs.Add(machine, initNode); }
/// <summary> /// Returns true if the given field symbol is being accessed /// before being reset. /// </summary> /// <param name="field">Field</param> /// <param name="summary">MethodSummary</param> /// <returns>Boolean value</returns> internal static bool IsAccessedBeforeBeingReset(ISymbol field, MethodSummary summary) { StateTransitionGraphNode stateTransitionNode = null; if (!AnalysisContext.StateTransitionGraphs.ContainsKey(summary.Machine)) { return(true); } stateTransitionNode = AnalysisContext.StateTransitionGraphs[summary.Machine]. GetGraphNodeForSummary(summary); if (stateTransitionNode == null) { return(true); } var result = stateTransitionNode.VisitSelfAndSuccessors(IsAccessedBeforeBeingReset, new Tuple <MethodSummary, ISymbol>(summary, field)); return(false); }
/// <summary> /// Tries to construct the state transition graph for the given machine. /// </summary> /// <param name="machine">Machine</param> private void ConstructGraphForMachine(ClassDeclarationSyntax machine) { var model = AnalysisContext.Compilation.GetSemanticModel(machine.SyntaxTree); Dictionary<ClassDeclarationSyntax, HashSet<ClassDeclarationSyntax>> stateTransitions = null; this.TryParseStateTransitions(out stateTransitions, machine, model); Dictionary<ClassDeclarationSyntax, HashSet<MethodDeclarationSyntax>> actionBindings = null; this.TryParseActionBindings(out actionBindings, machine, model); this.ComputeStatistics(stateTransitions, actionBindings); ClassDeclarationSyntax initState = null; foreach (var state in stateTransitions) { foreach (var attributeList in state.Key.AttributeLists) { foreach (var attribute in attributeList.Attributes) { if (attribute.Name.ToString().Equals("Microsoft.PSharp.Start")) { initState = state.Key; } } } } if (initState == null) { return; } var initNode = new StateTransitionGraphNode(this.AnalysisContext, initState, machine); initNode.IsStartNode = true; initNode.Construct(stateTransitions, actionBindings); AnalysisContext.StateTransitionGraphs.Add(machine, initNode); }
/// <summary> /// Constructs the node using information from the given state transitions /// and action bindings. /// </summary> /// <param name="stateTransitions">State transitions</param> /// <param name="actionBindings">Action bindings</param> /// <param name="visited">Already visited nodes</param> private void Construct(Dictionary<ClassDeclarationSyntax, HashSet<ClassDeclarationSyntax>> stateTransitions, Dictionary<ClassDeclarationSyntax, HashSet<MethodDeclarationSyntax>> actionBindings, HashSet<StateTransitionGraphNode> visited) { visited.Add(this); foreach (var method in this.State.ChildNodes().OfType<MethodDeclarationSyntax>()) { var summary = MethodSummary.Factory.Summarize(this.AnalysisContext, method); if (method.Modifiers.Any(SyntaxKind.OverrideKeyword) && method.Identifier.ValueText.Equals("OnEntry")) { this.OnEntry = summary; } else if (method.Modifiers.Any(SyntaxKind.OverrideKeyword) && method.Identifier.ValueText.Equals("OnExit")) { this.OnExit = summary; } } var actions = new HashSet<MethodDeclarationSyntax>(); if (actionBindings.ContainsKey(this.State)) { actions = actionBindings[this.State]; } foreach (var action in actions) { var actionSummary = MethodSummary.Factory.Summarize(this.AnalysisContext, action); this.Actions.Add(actionSummary); } var transitions = new HashSet<ClassDeclarationSyntax>(); if (stateTransitions.ContainsKey(this.State)) { transitions = stateTransitions[this.State]; } foreach (var successorState in transitions) { var successor = visited.FirstOrDefault(v => v.State.Equals(successorState)); if (successor != null) { this.ISuccessors.Add(successor); successor.IPredecessors.Add(this); } else { successor = new StateTransitionGraphNode(this.AnalysisContext, successorState, this.Machine); this.ISuccessors.Add(successor); successor.IPredecessors.Add(this); successor.Construct(stateTransitions, actionBindings, visited); } } }