/// <summary> /// Returns true if the given expression flows in the target. /// </summary> /// <param name="expr">Expression</param> /// <param name="target">Target</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> internal static bool FlowsIntoTarget(ExpressionSyntax expr, ISymbol target, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode, SemanticModel model, AnalysisContext context) { ISymbol reference = null; if (!context.TryGetSymbolFromExpression(out reference, expr, model)) { return false; } return DataFlowAnalysis.FlowsIntoTarget(reference, target, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode); }
/// <summary> /// Returns true if the given expression resets when flowing from the /// target in the given loop body control flow graph nodes. The given /// control flow graph nodes must be equal. /// </summary> /// <param name="expr">Expression</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean value</returns> internal static bool DoesResetInLoop(ExpressionSyntax expr, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode, SemanticModel model, AnalysisContext context) { ISymbol reference = null; if (!cfgNode.Equals(targetCfgNode) || !context.TryGetSymbolFromExpression(out reference, expr, model)) { return false; } return DataFlowAnalysis.DoesResetInLoop(reference, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode); }
/// <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> /// <param name="context">AnalysisContext</param> /// <returns>Boolean value</returns> internal static bool IsAccessedBeforeBeingReset(ISymbol field, MethodSummary summary, AnalysisContext context) { StateTransitionGraphNode stateTransitionNode = null; if (!context.StateTransitionGraphs.ContainsKey(summary.Machine)) { return true; } stateTransitionNode = context.StateTransitionGraphs[summary.Machine]. GetGraphNodeForSummary(summary); if (stateTransitionNode == null) { return true; } var result = stateTransitionNode.VisitSelfAndSuccessors(IsAccessedBeforeBeingReset, new Tuple<MethodSummary, ISymbol>(summary, field)); return false; }
/// <summary> /// Returns the data flow map for the given control flow graph. /// </summary> /// <param name="summary">MethodSummary</param> /// <param name="context">AnalysisContext</param> /// <returns>DataFlowMap</returns> internal static DataFlowMap AnalyseControlFlowGraph(MethodSummary summary, AnalysisContext context) { var dataFlowMap = new DataFlowMap(); var model = context.Compilation.GetSemanticModel(summary.Method.SyntaxTree); foreach (var param in summary.Method.ParameterList.Parameters) { var declType = model.GetTypeInfo(param.Type).Type; if (context.IsTypeAllowedToBeSend(declType) || context.IsMachineType(declType, model)) { continue; } var paramSymbol = model.GetDeclaredSymbol(param); dataFlowMap.MapRefToSymbol(paramSymbol, paramSymbol, summary.Method.ParameterList, summary.Node, false); } DataFlowAnalysis.AnalyseControlFlowGraphNode(summary.Node, summary.Node, summary.Method.ParameterList, dataFlowMap, model, context); return dataFlowMap; }
/// <summary> /// Constructor. /// </summary> /// <param name="context">AnalysisContext</param> private RuntimeOnlyDirectAccessAnalysis(AnalysisContext context) { this.AnalysisContext = context; }
/// <summary> /// Creates a new sanity checking analysis pass. /// </summary> /// <param name="context">AnalysisContext</param> /// <returns>SanityCheckingAnalysis</returns> public static SanityCheckingAnalysis Create(AnalysisContext context) { return new SanityCheckingAnalysis(context); }
/// <summary> /// Constructor. /// </summary> /// <param name="context">AnalysisContext</param> private SanityCheckingAnalysis(AnalysisContext context) { this.AnalysisContext = context; }
/// <summary> /// Registers immutable types. /// </summary> private static void RegisterImmutableTypes(AnalysisContext context) { context.RegisterImmutableType(typeof(MachineId)); }
/// <summary> /// Default constructor. /// </summary> /// <param name="context">AnalysisContext</param> /// <param name="summary">MethodSummary</param> internal ControlFlowGraphNode(AnalysisContext context, MethodSummary summary) { this.AnalysisContext = context; this.Id = ControlFlowGraphNode.IdCounter++; this.Summary = summary; this.SyntaxNodes = new List<SyntaxNode>(); this.IPredecessors = new HashSet<ControlFlowGraphNode>(); this.ISuccessors = new HashSet<ControlFlowGraphNode>(); this.IsGivesUpNode = false; this.IsJumpNode = false; this.IsLoopHeadNode = false; }
/// <summary> /// Constructor. /// </summary> /// <param name="context">AnalysisContext</param> private MethodSummaryAnalysis(AnalysisContext context) { this.AnalysisContext = context; }
/// <summary> /// Constructor. /// </summary> /// <param name="context">AnalysisContext</param> private RespectsOwnershipAnalysis(AnalysisContext context) { this.AnalysisContext = context; }
/// <summary> /// Tries to get the method summary of the given invocation. Returns /// null if such summary cannot be found. /// </summary> /// <param name="call">Call</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>MethodSummary</returns> internal static MethodSummary TryGetSummary(InvocationExpressionSyntax call, SemanticModel model, AnalysisContext context) { var callSymbol = model.GetSymbolInfo(call).Symbol; if (callSymbol == null) { return null; } if (callSymbol.ContainingType.ToString().Equals("Microsoft.PSharp.Machine") || callSymbol.ContainingType.ToString().Equals("Microsoft.PSharp.MachineState")) { return null; } var definition = SymbolFinder.FindSourceDefinitionAsync(callSymbol, context.Solution).Result; if (definition == null || definition.DeclaringSyntaxReferences.IsEmpty) { return null; } var invocationCall = definition.DeclaringSyntaxReferences.First().GetSyntax() as MethodDeclarationSyntax; return MethodSummary.Factory.Summarize(context, invocationCall); }
/// <summary> /// Tries to get the method summary of the given object creation. Returns /// null if such summary cannot be found. /// </summary> /// <param name="call">Call</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>MethodSummary</returns> internal static MethodSummary TryGetSummary(ObjectCreationExpressionSyntax call, SemanticModel model, AnalysisContext context) { var callSymbol = model.GetSymbolInfo(call).Symbol; if (callSymbol == null) { return null; } var definition = SymbolFinder.FindSourceDefinitionAsync(callSymbol, context.Solution).Result; if (definition == null) { return null; } if (definition.DeclaringSyntaxReferences.IsEmpty) { return null; } var constructorCall = definition.DeclaringSyntaxReferences.First().GetSyntax() as ConstructorDeclarationSyntax; return MethodSummary.Factory.Summarize(context, constructorCall); }
/// <summary> /// Constructor. /// </summary> /// <param name="context">AnalysisContext</param> /// <param name="method">Method</param> /// <param name="machine">Machine</param> /// <param name="state">State</param> private MethodSummary(AnalysisContext context, BaseMethodDeclarationSyntax method, ClassDeclarationSyntax machine, ClassDeclarationSyntax state) { this.AnalysisContext = context; this.Method = method; this.Machine = machine; this.State = state; this.Initialize(); }
/// <summary> /// Constructor. /// </summary> /// <param name="context">AnalysisContext</param> /// <param name="method">Method</param> private MethodSummary(AnalysisContext context, BaseMethodDeclarationSyntax method) { this.AnalysisContext = context; this.Method = method; this.Machine = null; this.State = null; this.Initialize(); }
/// <summary> /// Constructor. /// </summary> /// <param name="context">AnalysisContext</param> /// <param name="configuration">Configuration</param> /// <param name="logger">ILogger</param> /// <param name="errorReporter">ErrorReporter</param> private RespectsOwnershipAnalysisPass(AnalysisContext context, Configuration configuration, ILogger logger, ErrorReporter errorReporter) : base(context, configuration, logger, errorReporter) { }
/// <summary> /// Creates a new respects ownership analysis pass. /// </summary> /// <param name="context">AnalysisContext</param> /// <param name="configuration">Configuration</param> /// <param name="logger">ILogger</param> /// <param name="errorReporter">ErrorReporter</param> /// <returns>RespectsOwnershipAnalysisPass</returns> internal static RespectsOwnershipAnalysisPass Create(AnalysisContext context, Configuration configuration, ILogger logger, ErrorReporter errorReporter) { return(new RespectsOwnershipAnalysisPass(context, configuration, logger, errorReporter)); }
/// <summary> /// Constructor. /// </summary> /// <param name="context">AnalysisContext</param> private StateTransitionAnalysis(AnalysisContext context) { this.AnalysisContext = context; }
/// <summary> /// Creates a new state transition analysis pass. /// </summary> /// <param name="context">AnalysisContext</param> /// <returns>StateTransitionAnalysis</returns> public static StateTransitionAnalysis Create(AnalysisContext context) { return new StateTransitionAnalysis(context); }
/// <summary> /// Returns the summary of the given method. /// </summary> /// <param name="context">AnalysisContext</param> /// <param name="method">Method</param> /// <param name="machine">Machine</param> /// <param name="state">State</param> /// <returns>MethodSummary</returns> internal static MethodSummary Summarize(AnalysisContext context, BaseMethodDeclarationSyntax method, ClassDeclarationSyntax machine, ClassDeclarationSyntax state) { if (context.Summaries.ContainsKey(method)) { return context.Summaries[method]; } return new MethodSummary(context, method, machine, state); }
/// <summary> /// Creates a new respects ownership analysis pass. /// </summary> /// <param name="context">AnalysisContext</param> /// <returns>RespectsOwnershipAnalysis</returns> public static RespectsOwnershipAnalysis Create(AnalysisContext context) { return new RespectsOwnershipAnalysis(context); }
/// <summary> /// Tries to get the list of potential methods that can override the given virtual call. /// If it cannot find such methods then it returns false. /// </summary> /// <param name="overriders">List of overrider methods</param> /// <param name="virtualCall">Virtual call</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="originalMachine">Original machine</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> internal static bool TryGetPotentialMethodOverriders(out HashSet<MethodDeclarationSyntax> overriders, InvocationExpressionSyntax virtualCall, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, ClassDeclarationSyntax originalMachine, SemanticModel model, AnalysisContext context) { overriders = new HashSet<MethodDeclarationSyntax>(); ISymbol calleeSymbol = null; SimpleNameSyntax callee = null; bool isThis = false; if (virtualCall.Expression is MemberAccessExpressionSyntax) { var expr = virtualCall.Expression as MemberAccessExpressionSyntax; var identifier = expr.Expression.DescendantNodesAndSelf(). OfType<IdentifierNameSyntax>().Last(); calleeSymbol = model.GetSymbolInfo(identifier).Symbol; if (expr.Expression is ThisExpressionSyntax || context.IsMachineType(identifier, model)) { callee = expr.Name; isThis = true; } } else { callee = virtualCall.Expression as IdentifierNameSyntax; isThis = true; } if (isThis) { foreach (var nestedClass in originalMachine.ChildNodes().OfType<ClassDeclarationSyntax>()) { foreach (var method in nestedClass.ChildNodes().OfType<MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return true; } } } foreach (var method in originalMachine.ChildNodes().OfType<MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return true; } } return false; } if (calleeSymbol == null) { return false; } Dictionary<ISymbol, HashSet<ITypeSymbol>> objectTypeMap = null; if (!cfgNode.Summary.DataFlowMap.TryGetObjectTypeMapForSyntaxNode( syntaxNode, cfgNode, out objectTypeMap)) { return false; } if (!objectTypeMap.ContainsKey(calleeSymbol)) { return false; } foreach (var objectType in objectTypeMap[calleeSymbol]) { MethodDeclarationSyntax m = null; if (InheritanceAnalysis.TryGetMethodFromType(out m, objectType, virtualCall, context)) { overriders.Add(m); } } return true; }
/// <summary> /// Creates a new method summary analysis pass. /// </summary> /// <param name="context">AnalysisContext</param> /// <returns>MethodSummaryAnalysis</returns> public static MethodSummaryAnalysis Create(AnalysisContext context) { return new MethodSummaryAnalysis(context); }
/// <summary> /// Tries to capture a potential parameter acccess in the given expression. /// </summary> /// <param name="expr">Expression</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> private static void TryCaptureParameterAccess(ExpressionSyntax expr, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!(expr is MemberAccessExpressionSyntax)) { return; } var name = (expr as MemberAccessExpressionSyntax).Name; var identifier = context.GetFirstNonMachineIdentifier(expr, model); if (identifier == null || name == null) { return; } var type = model.GetTypeInfo(identifier).Type; if (context.IsTypeAllowedToBeSend(type) || context.IsMachineType(type, model) || name.Equals(identifier)) { return; } var symbol = model.GetSymbolInfo(identifier).Symbol; if (symbol == null) { return; } Dictionary<ISymbol, HashSet<ISymbol>> map = null; if (!dataFlowMap.TryGetMapForSyntaxNode(syntaxNode, cfgNode, out map)) { return; } Dictionary<ISymbol, int> indexMap = new Dictionary<ISymbol, int>(); var parameterList = cfgNode.Summary.Method.ParameterList.Parameters; for (int idx = 0; idx < parameterList.Count; idx++) { var paramSymbol = model.GetDeclaredSymbol(parameterList[idx]); indexMap.Add(paramSymbol, idx); } if (map.ContainsKey(symbol)) { foreach (var reference in map[symbol]) { if (reference.Kind == SymbolKind.Parameter) { if (reference.Equals(symbol) && dataFlowMap.DoesSymbolReset( reference, cfgNode.Summary.Node.SyntaxNodes.First(), cfgNode.Summary.Node, syntaxNode, cfgNode, true)) { continue; } int index = indexMap[reference]; if (cfgNode.Summary.AccessSet.ContainsKey(index)) { cfgNode.Summary.AccessSet[index].Add(syntaxNode); } else { cfgNode.Summary.AccessSet.Add(index, new HashSet<SyntaxNode>()); cfgNode.Summary.AccessSet[index].Add(syntaxNode); } } } } }
/// <summary> /// Tries to get the method from the given type and virtual call. /// </summary> /// <param name="method">Method</param> /// <param name="type">Type</param> /// <param name="virtualCall">Virtual call</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> private static bool TryGetMethodFromType(out MethodDeclarationSyntax method, ITypeSymbol type, InvocationExpressionSyntax virtualCall, AnalysisContext context) { method = null; var definition = SymbolFinder.FindSourceDefinitionAsync(type, context.Solution).Result; if (definition == null) { return false; } var calleeClass = definition.DeclaringSyntaxReferences.First().GetSyntax() as ClassDeclarationSyntax; foreach (var m in calleeClass.ChildNodes().OfType<MethodDeclarationSyntax>()) { if (m.Identifier.ValueText.Equals(context.GetCallee(virtualCall))) { method = m; break; } } return true; }
/// <summary> /// Analyzes the given P# project. /// </summary> private void AnalyzeProject(Project project) { // Starts profiling the analysis. if (this.CompilationContext.Configuration.EnableProfiling) { this.Profiler.StartMeasuringExecutionTime(); } // Create a state-machine static analysis context. var context = AnalysisContext.Create(project); this.PerformErrorChecking(context); RegisterImmutableTypes(context); RegisterGivesUpOwnershipOperations(context); // Creates and runs an analysis pass that computes the // summaries for every P# machine. ISet <StateMachine> machines = new HashSet <StateMachine>(); try { // Creates summaries for each machine, which can be used for subsequent // analyses. Optionally performs data-flow analysis. MachineSummarizationPass.Create(context, this.CompilationContext.Configuration, this.Logger, this.ErrorReporter).Run(machines); // Creates and runs an analysis pass that detects if a machine contains // states that are declared as generic. This is not allowed by P#. NoGenericStatesAnalysisPass.Create(context, this.CompilationContext.Configuration, this.Logger, this.ErrorReporter).Run(machines); // Creates and runs an analysis pass that finds if a machine exposes // any fields or methods to other machines. DirectAccessAnalysisPass.Create(context, this.CompilationContext.Configuration, this.Logger, this.ErrorReporter).Run(machines); if (this.CompilationContext.Configuration.AnalyzeDataRaces) { // Creates and runs an analysis pass that detects if any method // in each machine is erroneously giving up ownership. GivesUpOwnershipAnalysisPass.Create(context, this.CompilationContext.Configuration, this.Logger, this.ErrorReporter).Run(machines); // Creates and runs an analysis pass that detects if all methods // in each machine respect given up ownerships. RespectsOwnershipAnalysisPass.Create(context, this.CompilationContext.Configuration, this.Logger, this.ErrorReporter).Run(machines); } } catch (Exception ex) { if (this.CompilationContext.Configuration.ThrowInternalExceptions) { #pragma warning disable CA2200 // Rethrow to preserve stack details. throw ex; #pragma warning restore CA2200 // Rethrow to preserve stack details. } this.Logger.WriteLine($"... Failed to analyze project '{project.Name}'"); if (this.CompilationContext.Configuration.EnableDebugging) { this.Logger.WriteLine(ex.ToString()); } } finally { // Stops profiling the analysis. if (this.CompilationContext.Configuration.EnableProfiling) { this.Profiler.StopMeasuringExecutionTime(); this.Logger.WriteLine("... Total static analysis runtime: '" + this.Profiler.Results() + "' seconds."); } } }
/// <summary> /// Checks if the gives up call has a field symbol argument that is not /// already mapped and, if yes, maps it. /// </summary> /// <param name="call">Call</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> private static void CheckForNonMappedFieldSymbol(InvocationExpressionSyntax call, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!cfgNode.IsGivesUpNode) { return; } List<MemberAccessExpressionSyntax> accesses; if (cfgNode.Summary.GivesUpSet.Count == 0 && call.Expression.DescendantNodesAndSelf(). OfType<IdentifierNameSyntax>().Last().ToString().Equals("Send")) { accesses = call.ArgumentList.Arguments[1].DescendantNodesAndSelf(). OfType<MemberAccessExpressionSyntax>().ToList(); } else { accesses = call.ArgumentList.DescendantNodesAndSelf().OfType<MemberAccessExpressionSyntax>().ToList(); } foreach (var access in accesses) { IdentifierNameSyntax id = context.GetFirstNonMachineIdentifier(access, model); if (id == null) { continue; } var accessSymbol = model.GetSymbolInfo(id).Symbol; dataFlowMap.MapSymbolIfNotExists(accessSymbol, cfgNode.SyntaxNodes[0], cfgNode); } }
/// <summary> /// Default constructor. /// </summary> /// <param name="context">AnalysisContext</param> /// <param name="machine">Machine</param> internal StateTransitionGraphNode(AnalysisContext context, ClassDeclarationSyntax state, ClassDeclarationSyntax machine) { this.AnalysisContext = context; this.Id = StateTransitionGraphNode.IdCounter++; this.State = state; this.Machine = machine; this.Actions = new HashSet<MethodSummary>(); this.IPredecessors = new HashSet<StateTransitionGraphNode>(); this.ISuccessors = new HashSet<StateTransitionGraphNode>(); this.IsStartNode = false; }
/// <summary> /// Tries to capture a potential field acccess in the given expression. /// </summary> /// <param name="expr">Expression</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> private static void TryCaptureFieldAccess(ExpressionSyntax expr, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!(expr is MemberAccessExpressionSyntax)) { return; } var name = (expr as MemberAccessExpressionSyntax).Name; var identifier = context.GetFirstNonMachineIdentifier(expr, model); if (identifier == null || name == null) { return; } var type = model.GetTypeInfo(identifier).Type; if (context.IsTypeAllowedToBeSend(type) || context.IsMachineType(type, model) || name.Equals(identifier)) { return; } var symbol = model.GetSymbolInfo(identifier).Symbol; var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, context.Solution).Result; if (!(definition is IFieldSymbol)) { return; } var fieldDecl = definition.DeclaringSyntaxReferences.First().GetSyntax(). AncestorsAndSelf().OfType<FieldDeclarationSyntax>().First(); if (dataFlowMap.DoesSymbolReset(symbol, cfgNode.Summary.Node.SyntaxNodes.First(), cfgNode.Summary.Node, syntaxNode, cfgNode, true)) { return; } if (cfgNode.Summary.FieldAccessSet.ContainsKey(symbol as IFieldSymbol)) { cfgNode.Summary.FieldAccessSet[symbol as IFieldSymbol].Add(syntaxNode); } else { cfgNode.Summary.FieldAccessSet.Add(symbol as IFieldSymbol, new HashSet<SyntaxNode>()); cfgNode.Summary.FieldAccessSet[symbol as IFieldSymbol].Add(syntaxNode); } }
/// <summary> /// Creates a new runtime only direct access analysis pass. /// </summary> /// <param name="context">AnalysisContext</param> /// <returns>RuntimeOnlyDirectAccessAnalysis</returns> public static RuntimeOnlyDirectAccessAnalysis Create(AnalysisContext context) { return new RuntimeOnlyDirectAccessAnalysis(context); }
/// <summary> /// Performs data flow analysis on the given control flow graph node. /// </summary> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="previousCfgNode">Previous controlFlowGraphNode</param> /// <param name="previousSyntaxNode">Previous syntaxNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> private static void AnalyseControlFlowGraphNode(ControlFlowGraphNode cfgNode, ControlFlowGraphNode previousCfgNode, SyntaxNode previousSyntaxNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!cfgNode.IsJumpNode && !cfgNode.IsLoopHeadNode) { foreach (var syntaxNode in cfgNode.SyntaxNodes) { dataFlowMap.Transfer(previousSyntaxNode, previousCfgNode, syntaxNode, cfgNode); var stmt = syntaxNode as StatementSyntax; var localDecl = stmt.DescendantNodesAndSelf().OfType<LocalDeclarationStatementSyntax>().FirstOrDefault(); var expr = stmt.DescendantNodesAndSelf().OfType<ExpressionStatementSyntax>().FirstOrDefault(); var ret = stmt.DescendantNodesAndSelf().OfType<ReturnStatementSyntax>().FirstOrDefault(); if (localDecl != null) { var varDecl = (stmt as LocalDeclarationStatementSyntax).Declaration; foreach (var variable in varDecl.Variables) { if (variable.Initializer == null) { continue; } DataFlowAnalysis.TryCaptureParameterAccess(variable.Initializer.Value, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(variable.Initializer.Value, syntaxNode, cfgNode, dataFlowMap, model, context); ITypeSymbol declType = null; if (variable.Initializer.Value is LiteralExpressionSyntax && variable.Initializer.Value.IsKind(SyntaxKind.NullLiteralExpression)) { declType = model.GetTypeInfo(varDecl.Type).Type; } else { declType = model.GetTypeInfo(variable.Initializer.Value).Type; } if (context.IsTypeAllowedToBeSend(declType) || context.IsMachineType(declType, model)) { continue; } var declSymbol = model.GetDeclaredSymbol(variable); if (variable.Initializer.Value is IdentifierNameSyntax || variable.Initializer.Value is MemberAccessExpressionSyntax) { ISymbol varSymbol = null; if (variable.Initializer.Value is IdentifierNameSyntax) { varSymbol = model.GetSymbolInfo(variable.Initializer.Value as IdentifierNameSyntax).Symbol; } else if (variable.Initializer.Value is MemberAccessExpressionSyntax) { varSymbol = model.GetSymbolInfo((variable.Initializer.Value as MemberAccessExpressionSyntax).Name).Symbol; } dataFlowMap.MapRefToSymbol(varSymbol, declSymbol, syntaxNode, cfgNode); HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, varSymbol, syntaxNode, cfgNode, dataFlowMap)) { dataFlowMap.MapObjectTypesToSymbol(objectTypes, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } else if (variable.Initializer.Value is LiteralExpressionSyntax && variable.Initializer.Value.IsKind(SyntaxKind.NullLiteralExpression)) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (variable.Initializer.Value is InvocationExpressionSyntax) { var invocation = variable.Initializer.Value as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (returnSymbols.Contains(declSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode, false); } else { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode); } if (reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, declSymbol, syntaxNode, cfgNode); } if (summary != null && summary.ReturnTypeSet.Count > 0) { dataFlowMap.MapObjectTypesToSymbol(summary.ReturnTypeSet, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } else if (variable.Initializer.Value is ObjectCreationExpressionSyntax) { var objCreation = variable.Initializer.Value as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (returnSymbols.Contains(declSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode, false); } else { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode); } if (reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, declSymbol, syntaxNode, cfgNode); } var typeSymbol = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (typeSymbol != null) { dataFlowMap.MapObjectTypesToSymbol(new HashSet<ITypeSymbol> { typeSymbol }, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } } } else if (expr != null) { if (expr.Expression is BinaryExpressionSyntax) { var binaryExpr = expr.Expression as BinaryExpressionSyntax; DataFlowAnalysis.TryCaptureParameterAccess(binaryExpr.Left, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureParameterAccess(binaryExpr.Right, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(binaryExpr.Left, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(binaryExpr.Right, syntaxNode, cfgNode, dataFlowMap, model, context); IdentifierNameSyntax lhs = null; ISymbol lhsFieldSymbol = null; if (binaryExpr.Left is IdentifierNameSyntax) { lhs = binaryExpr.Left as IdentifierNameSyntax; var lhsType = model.GetTypeInfo(lhs).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } } else if (binaryExpr.Left is MemberAccessExpressionSyntax) { var name = (binaryExpr.Left as MemberAccessExpressionSyntax).Name; var lhsType = model.GetTypeInfo(name).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } lhs = context.GetFirstNonMachineIdentifier(binaryExpr.Left, model); lhsFieldSymbol = model.GetSymbolInfo(name as IdentifierNameSyntax).Symbol; } else if (binaryExpr.Left is ElementAccessExpressionSyntax) { var memberAccess = (binaryExpr.Left as ElementAccessExpressionSyntax); if (memberAccess.Expression is IdentifierNameSyntax) { lhs = memberAccess.Expression as IdentifierNameSyntax; var lhsType = model.GetTypeInfo(lhs).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } } else if (memberAccess.Expression is MemberAccessExpressionSyntax) { var name = (memberAccess.Expression as MemberAccessExpressionSyntax).Name; var lhsType = model.GetTypeInfo(name).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } lhs = context.GetFirstNonMachineIdentifier(memberAccess.Expression, model); lhsFieldSymbol = model.GetSymbolInfo(name as IdentifierNameSyntax).Symbol; } } var leftSymbol = model.GetSymbolInfo(lhs).Symbol; if (binaryExpr.Right is IdentifierNameSyntax || binaryExpr.Right is MemberAccessExpressionSyntax) { IdentifierNameSyntax rhs = null; if (binaryExpr.Right is IdentifierNameSyntax) { rhs = binaryExpr.Right as IdentifierNameSyntax; } else if (binaryExpr.Right is MemberAccessExpressionSyntax) { rhs = context.GetFirstNonMachineIdentifier(binaryExpr.Right, model); } var rightSymbol = model.GetSymbolInfo(rhs).Symbol; dataFlowMap.MapRefToSymbol(rightSymbol, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefToSymbol(rightSymbol, lhsFieldSymbol, syntaxNode, cfgNode); } HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, rightSymbol, syntaxNode, cfgNode, dataFlowMap)) { dataFlowMap.MapObjectTypesToSymbol(objectTypes, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is LiteralExpressionSyntax && binaryExpr.Right.IsKind(SyntaxKind.NullLiteralExpression)) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is InvocationExpressionSyntax) { var invocation = binaryExpr.Right as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); DataFlowAnalysis.CheckForNonMappedFieldSymbol(invocation, cfgNode, dataFlowMap, model, context); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (returnSymbols.Contains(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode, false); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode, false); } } else { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } } if (lhsFieldSymbol != null && reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } if (summary != null && summary.ReturnTypeSet.Count > 0) { dataFlowMap.MapObjectTypesToSymbol(summary.ReturnTypeSet, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is ObjectCreationExpressionSyntax) { var objCreation = binaryExpr.Right as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (returnSymbols.Contains(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode, false); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode, false); } } else { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } } if (lhsFieldSymbol != null && reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } var typeSymbol = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (typeSymbol != null) { dataFlowMap.MapObjectTypesToSymbol(new HashSet<ITypeSymbol> { typeSymbol }, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } } else if (expr.Expression is InvocationExpressionSyntax) { var invocation = expr.Expression as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); DataFlowAnalysis.CheckForNonMappedFieldSymbol(invocation, cfgNode, dataFlowMap, model, context); } } else if (ret != null) { HashSet<ISymbol> returnSymbols = null; if (ret.Expression is IdentifierNameSyntax || ret.Expression is MemberAccessExpressionSyntax) { IdentifierNameSyntax rhs = null; if (ret.Expression is IdentifierNameSyntax) { rhs = ret.Expression as IdentifierNameSyntax; } else if (ret.Expression is MemberAccessExpressionSyntax) { rhs = context.GetFirstNonMachineIdentifier(ret.Expression, model); } var rightSymbol = model.GetSymbolInfo(rhs).Symbol; returnSymbols = new HashSet<ISymbol> { rightSymbol }; HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, rightSymbol, syntaxNode, cfgNode, dataFlowMap)) { foreach (var objectType in objectTypes) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } } else if (ret.Expression is InvocationExpressionSyntax) { var invocation = ret.Expression as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); if (summary != null) { foreach (var objectType in summary.ReturnTypeSet) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } } else if (ret.Expression is ObjectCreationExpressionSyntax) { var objCreation = ret.Expression as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); var objectType = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (objectType != null) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } DataFlowAnalysis.TryCaptureReturnSymbols(returnSymbols, syntaxNode, cfgNode, model, dataFlowMap); } previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; } } else { dataFlowMap.Transfer(previousSyntaxNode, previousCfgNode, cfgNode.SyntaxNodes[0], cfgNode); previousSyntaxNode = cfgNode.SyntaxNodes[0]; previousCfgNode = cfgNode; } foreach (var successor in cfgNode.ISuccessors) { if (DataFlowAnalysis.ReachedFixpoint(previousSyntaxNode, cfgNode, successor, dataFlowMap)) { continue; } DataFlowAnalysis.AnalyseControlFlowGraphNode(successor, cfgNode, previousSyntaxNode, dataFlowMap, model, context); } }
/// <summary> /// Constructor. /// </summary> /// <param name="methodDecl">MethodDeclarationSyntax</param> /// <param name="state">MachineState</param> /// <param name="context">AnalysisContext</param> internal OnEntryMachineAction(MethodDeclarationSyntax methodDecl, MachineState state, AnalysisContext context) : base(methodDecl, state, context) { }