/// <summary> /// Runs the analysis. /// </summary> public static void Run() { foreach (var machine in AnalysisContext.Machines) { StateTransitionAnalysis.ConstructGraphForMachine(machine); } }
/// <summary> /// Tries to parse and return the state transitions for the given machine. /// </summary> /// <param name="stateTransitions">State transitions</param> /// <param name="machine">Machine</param> /// <param name="model">SemanticModel</param> /// <returns>Boolean value</returns> private static bool TryParseStateTransitions(out Dictionary <ClassDeclarationSyntax, HashSet <ClassDeclarationSyntax> > stateTransitions, ClassDeclarationSyntax machine, SemanticModel model) { stateTransitions = new Dictionary <ClassDeclarationSyntax, HashSet <ClassDeclarationSyntax> >(); var defineGotoStateTransitionsMethod = machine.ChildNodes(). OfType <MethodDeclarationSyntax>().FirstOrDefault(v => v.Identifier.ValueText.Equals("DefineGotoStateTransitions") && v.Modifiers.Any(SyntaxKind.OverrideKeyword) && v.ReturnType.ToString(). Equals("System.Collections.Generic.Dictionary<Type, GotoStateTransitions>")); if (defineGotoStateTransitionsMethod == null) { return(false); } var returnStmt = defineGotoStateTransitionsMethod.DescendantNodes(). OfType <ReturnStatementSyntax>().First(); var returnSymbol = model.GetSymbolInfo(returnStmt.Expression).Symbol; Dictionary <ClassDeclarationSyntax, IdentifierNameSyntax> stateMap = null; if (!StateTransitionAnalysis.TryParseStateMap(out stateMap, returnSymbol, defineGotoStateTransitionsMethod, model)) { return(false); } foreach (var state in stateMap) { if (state.Value == null) { continue; } var dictionarySymbol = model.GetSymbolInfo(state.Value).Symbol; var dictionaryInvocations = StateTransitionAnalysis.GetInvocationsFromSymbol( dictionarySymbol, defineGotoStateTransitionsMethod); var transitions = ParseTransitions(dictionarySymbol, defineGotoStateTransitionsMethod, model); if (transitions.Count == 0) { continue; } stateTransitions.Add(state.Key, transitions); } return(true); }
/// <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> /// Parses and returns the state map from the given symbol. /// </summary> /// <param name="stateMap">State map</param> /// <param name="symbol">Symbol</param> /// <param name="method">Method</param> /// <param name="model">SemanticModel</param> /// <returns>Boolean value</returns> private static bool TryParseStateMap(out Dictionary <ClassDeclarationSyntax, IdentifierNameSyntax> stateMap, ISymbol symbol, MethodDeclarationSyntax method, SemanticModel model) { stateMap = new Dictionary <ClassDeclarationSyntax, IdentifierNameSyntax>(); var invocations = StateTransitionAnalysis.GetInvocationsFromSymbol(symbol, method); foreach (var inv in invocations) { if (!(inv.Expression is MemberAccessExpressionSyntax)) { continue; } var expr = inv.Expression as MemberAccessExpressionSyntax; if (!expr.Name.ToString().Equals("Add")) { continue; } var stateType = (inv.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax).Type as IdentifierNameSyntax; var dictionary = inv.ArgumentList.Arguments[1].Expression as IdentifierNameSyntax; var stateSymbol = model.GetTypeInfo(stateType).Type; var stateDefinition = SymbolFinder.FindSourceDefinitionAsync(stateSymbol, ProgramInfo.Solution).Result; if (stateDefinition == null) { return(false); } var state = stateDefinition.DeclaringSyntaxReferences.First().GetSyntax() as ClassDeclarationSyntax; stateMap.Add(state, dictionary); } return(true); }
/// <summary> /// Parses and returns the list of actions from the given symbol. /// </summary> /// <param name="actions">List of actions</param> /// <param name="symbol">Symbol</param> /// <param name="method">Method</param> /// <param name="model">SemanticModel</param> /// <returns>Set of actions</returns> private static HashSet <MethodDeclarationSyntax> ParseActions(ISymbol symbol, MethodDeclarationSyntax method, SemanticModel model) { var actions = new HashSet <MethodDeclarationSyntax>(); var invocations = StateTransitionAnalysis.GetInvocationsFromSymbol(symbol, method); foreach (var inv in invocations) { if (!(inv.Expression is MemberAccessExpressionSyntax)) { continue; } var expr = inv.Expression as MemberAccessExpressionSyntax; if (!expr.Name.ToString().Equals("Add")) { continue; } var actionType = (inv.ArgumentList.Arguments[1].Expression as ObjectCreationExpressionSyntax).ArgumentList.Arguments[0]. Expression as IdentifierNameSyntax; var actionSymbol = model.GetSymbolInfo(actionType).Symbol; var actionDefinition = SymbolFinder.FindSourceDefinitionAsync(actionSymbol, ProgramInfo.Solution).Result; if (actionDefinition == null) { continue; } var action = actionDefinition.DeclaringSyntaxReferences.First().GetSyntax() as MethodDeclarationSyntax; actions.Add(action); } return(actions); }