/// <summary> /// Analyzes the ownership of the given-up symbol /// in the call. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="call">ExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> /// <returns>Set of return symbols</returns> protected HashSet <ISymbol> AnalyzeOwnershipInCall(GivenUpOwnershipSymbol givenUpSymbol, ExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { var potentialReturnSymbols = new HashSet <ISymbol>(); var invocation = call as InvocationExpressionSyntax; var objCreation = call as ObjectCreationExpressionSyntax; if ((invocation == null && objCreation == null)) { return(potentialReturnSymbols); } TraceInfo callTrace = new TraceInfo(); callTrace.Merge(trace); callTrace.AddErrorTrace(call); var callSymbol = model.GetSymbolInfo(call).Symbol; if (callSymbol == null) { base.ErrorReporter.ReportExternalInvocation(callTrace); return(potentialReturnSymbols); } if (callSymbol.ContainingType.ToString().Equals("Microsoft.PSharp.Machine")) { this.AnalyzeOwnershipInGivesUpCall(givenUpSymbol, invocation, statement, machine, model, callTrace); return(potentialReturnSymbols); } if (SymbolFinder.FindSourceDefinitionAsync(callSymbol, this.AnalysisContext.Solution).Result == null) { base.ErrorReporter.ReportExternalInvocation(callTrace); return(potentialReturnSymbols); } var candidateSummaries = MethodSummary.GetCachedSummaries(callSymbol, statement); foreach (var candidateSummary in candidateSummaries) { this.AnalyzeOwnershipInCandidateCallee(givenUpSymbol, candidateSummary, call, statement, machine, model, callTrace); if (invocation != null) { var resolvedReturnSymbols = candidateSummary.GetResolvedReturnSymbols(invocation, model); foreach (var resolvedReturnSymbol in resolvedReturnSymbols) { potentialReturnSymbols.Add(resolvedReturnSymbol); } } } return(potentialReturnSymbols); }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the control-flow graph node. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected void AnalyzeOwnershipInStatement(GivenUpOwnershipSymbol givenUpSymbol, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { var localDecl = statement.SyntaxNode.DescendantNodesAndSelf(). OfType <LocalDeclarationStatementSyntax>().FirstOrDefault(); var expr = statement.SyntaxNode.DescendantNodesAndSelf(). OfType <ExpressionStatementSyntax>().FirstOrDefault(); if (localDecl != null) { var varDecl = localDecl.Declaration; this.AnalyzeOwnershipInLocalDeclaration(givenUpSymbol, varDecl, statement, machine, model, trace); } else if (expr != null) { if (expr.Expression is AssignmentExpressionSyntax) { var assignment = expr.Expression as AssignmentExpressionSyntax; this.AnalyzeOwnershipInAssignment(givenUpSymbol, assignment, statement, machine, model, trace); } else if (expr.Expression is InvocationExpressionSyntax || expr.Expression is ObjectCreationExpressionSyntax) { trace.InsertCall(statement.Summary.Method, expr.Expression); this.AnalyzeOwnershipInCall(givenUpSymbol, expr.Expression, statement, machine, model, trace); } } }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the expression. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="expr">ExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> private void AnalyzeOwnershipInExpression(GivenUpOwnershipSymbol givenUpSymbol, ExpressionSyntax expr, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { if (expr is IdentifierNameSyntax || expr is MemberAccessExpressionSyntax) { IdentifierNameSyntax rightIdentifier = base.AnalysisContext.GetRootIdentifier(expr); if (rightIdentifier != null) { var rightSymbol = model.GetSymbolInfo(rightIdentifier).Symbol; this.AnalyzeGivingUpFieldOwnership(givenUpSymbol, rightSymbol, statement, machine, trace); } } else if (expr is InvocationExpressionSyntax || expr is ObjectCreationExpressionSyntax) { trace.InsertCall(statement.Summary.Method, expr); HashSet <ISymbol> returnSymbols = base.AnalyzeOwnershipInCall(givenUpSymbol, expr, statement, machine, model, trace); foreach (var returnSymbol in returnSymbols) { this.AnalyzeGivingUpFieldOwnership(givenUpSymbol, returnSymbol, statement, machine, trace); } } }
/// <summary> /// Checks the methods of each machine and report warnings if /// any method is directly accessed by anything else than the /// P# runtime. /// </summary> /// <param name="machines">StateMachines</param> private void CheckMethods(ISet <StateMachine> machines) { foreach (var machine in machines) { foreach (var method in machine.Declaration.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (method.Modifiers.Any(SyntaxKind.PublicKeyword)) { TraceInfo trace = new TraceInfo(); trace.AddErrorTrace(method.Identifier); AnalysisErrorReporter.ReportWarning(trace, "Method '{0}' of machine '{1}' " + "is declared as 'public'.", method.Identifier.ValueText, machine.Name); } else if (method.Modifiers.Any(SyntaxKind.InternalKeyword)) { TraceInfo trace = new TraceInfo(); trace.AddErrorTrace(method.Identifier); AnalysisErrorReporter.ReportWarning(trace, "Method '{0}' of machine '{1}' " + "is declared as 'internal'.", method.Identifier.ValueText, machine.Name); } } } }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the assignment expression. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="assignment">AssignmentExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected override void AnalyzeOwnershipInAssignment(GivenUpOwnershipSymbol givenUpSymbol, AssignmentExpressionSyntax assignment, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { var leftIdentifier = base.AnalysisContext.GetRootIdentifier(assignment.Left); ISymbol leftSymbol = model.GetSymbolInfo(leftIdentifier).Symbol; if (assignment.Right is IdentifierNameSyntax) { var rightIdentifier = base.AnalysisContext.GetRootIdentifier(assignment.Right); ISymbol rightSymbol = model.GetSymbolInfo(rightIdentifier).Symbol; if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(rightSymbol, givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement)) { var type = model.GetTypeInfo(assignment.Right).Type; if (leftSymbol != null && leftSymbol.Kind == SymbolKind.Field && base.IsFieldAccessedInSuccessor(leftSymbol as IFieldSymbol, statement.Summary, machine) && !base.AnalysisContext.IsTypePassedByValueOrImmutable(type)) { TraceInfo newTrace = new TraceInfo(); newTrace.Merge(trace); newTrace.AddErrorTrace(statement.SyntaxNode); AnalysisErrorReporter.ReportGivenUpOwnershipFieldAssignment(newTrace, leftSymbol); } return; } } else if (assignment.Right is MemberAccessExpressionSyntax) { this.AnalyzeOwnershipInExpression(givenUpSymbol, assignment.Right, statement, machine, model, trace); } else if (assignment.Right is InvocationExpressionSyntax || assignment.Right is ObjectCreationExpressionSyntax) { trace.InsertCall(statement.Summary.Method, assignment.Right); base.AnalyzeOwnershipInCall(givenUpSymbol, assignment.Right, statement, machine, model, trace); } if (assignment.Left is MemberAccessExpressionSyntax) { ISymbol outerLeftMemberSymbol = model.GetSymbolInfo(assignment.Left).Symbol; if (!outerLeftMemberSymbol.Equals(leftSymbol) && statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(givenUpSymbol.ContainingSymbol, leftSymbol, givenUpSymbol.Statement, statement)) { TraceInfo newTrace = new TraceInfo(); newTrace.Merge(trace); newTrace.AddErrorTrace(statement.SyntaxNode); AnalysisErrorReporter.ReportGivenUpOwnershipAccess(newTrace); } } }
/// <summary> /// Merges the given trace to the current trace. /// </summary> internal void Merge(TraceInfo traceInfo) { this.ErrorTrace.AddRange(traceInfo.ErrorTrace); this.CallTrace.AddRange(traceInfo.CallTrace); this.Method = traceInfo.Method; this.Machine = traceInfo.Machine; this.State = traceInfo.State; this.Payload = traceInfo.Payload; }
/// <summary> /// Reports an error to the user. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="s">String</param> internal static void Report(TraceInfo trace, string s) { Report(s); for (int idx = trace.ErrorTrace.Count - 1; idx >= 0; idx--) { IO.Print(" at '{0}' ", trace.ErrorTrace[idx].Expression); IO.Print("in {0}:", trace.ErrorTrace[idx].File); IO.PrintLine("line {0}", trace.ErrorTrace[idx].Line); } }
/// <summary> /// Reports a warning to the user. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="s">String</param> /// <param name="args">Parameters</param> internal static void ReportWarning(TraceInfo trace, string s, params object[] args) { ReportWarning(s, args); if (ErrorReporter.ShowWarnings) { IO.Print(" at '{0}' ", trace.ErrorTrace[trace.ErrorTrace.Count - 1].Expression); IO.Print("in {0}:", trace.ErrorTrace[trace.ErrorTrace.Count - 1].File); IO.PrintLine("line {0}", trace.ErrorTrace[trace.ErrorTrace.Count - 1].Line); } }
/// <summary> /// Reports an error to the user. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="s">String</param> internal void Report(TraceInfo trace, string s) { this.Report(s); for (int idx = trace.ErrorTrace.Count - 1; idx >= 0; idx--) { this.Logger.Write(" at '{0}' ", trace.ErrorTrace[idx].Expression); this.Logger.Write("in {0}:", trace.ErrorTrace[idx].File); this.Logger.WriteLine("line {0}", trace.ErrorTrace[idx].Line); } }
/// <summary> /// Reports a warning to the user. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="s">String</param> /// <param name="args">Parameters</param> internal void ReportWarning(TraceInfo trace, string s, params object[] args) { this.ReportWarning(s, args); if (this.Configuration.ShowWarnings) { this.Logger.Write(" at '{0}' ", trace.ErrorTrace[trace.ErrorTrace.Count - 1].Expression); this.Logger.Write("in {0}:", trace.ErrorTrace[trace.ErrorTrace.Count - 1].File); this.Logger.WriteLine("line {0}", trace.ErrorTrace[trace.ErrorTrace.Count - 1].Line); } }
/// <summary> /// Reports a warning to the user. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="message">Message</param> private static void ReportWarningTrace(TraceInfo trace, string message) { if (ReportedMessages.Contains(message)) { return; } ReportWarning(message); PrintTrace(trace); ReportedMessages.Add(message); }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the assignment expression. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="assignment">AssignmentExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected override void AnalyzeOwnershipInAssignment(GivenUpOwnershipSymbol givenUpSymbol, AssignmentExpressionSyntax assignment, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { IdentifierNameSyntax leftIdentifier = base.AnalysisContext.GetRootIdentifier(assignment.Left); ISymbol leftSymbol = model.GetSymbolInfo(leftIdentifier).Symbol; this.AnalyzeGivingUpFieldOwnership(givenUpSymbol, leftSymbol, statement, machine, trace); this.AnalyzeOwnershipInExpression(givenUpSymbol, assignment.Right, statement, machine, model, trace); }
/// <summary> /// Reports an error to the user. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="message">Message</param> /// <param name="allowMultiple">Allow multiple messages</param> private void ReportErrorTrace(TraceInfo trace, string message, bool allowMultiple = false) { if (!allowMultiple && this.ReportedMessages.Contains(message)) { return; } this.Report(message); this.PrintTrace(trace); this.ReportedMessages.Add(message); }
/// <summary> /// Reports a warning to the user. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="message">Message</param> private void ReportWarningTrace(TraceInfo trace, string message) { if (this.ReportedMessages.Contains(message)) { return; } this.ReportWarning(message); this.PrintTrace(trace); this.ReportedMessages.Add(message); }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the gives-up operation. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="call">Gives-up call</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected override void AnalyzeOwnershipInGivesUpCall(GivenUpOwnershipSymbol givenUpSymbol, InvocationExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { if (givenUpSymbol.Statement.Equals(statement) && givenUpSymbol.ContainingSymbol.Kind == SymbolKind.Field && base.IsFieldAccessedInSuccessor(givenUpSymbol.ContainingSymbol as IFieldSymbol, statement.Summary, machine)) { base.ErrorReporter.ReportGivenUpFieldOwnershipError(trace, givenUpSymbol.ContainingSymbol); } }
/// <summary> /// Analyzes the method summaries of the machine to check if /// each summary respects given-up ownerships. /// </summary> private void AnalyzeMethodSummariesInMachine(StateMachine machine) { foreach (var summary in machine.MethodSummaries.Values) { foreach (var givenUpSymbol in summary.GetSymbolsWithGivenUpOwnership()) { TraceInfo trace = new TraceInfo(summary.Method, machine, null, givenUpSymbol.ContainingSymbol); trace.AddErrorTrace(givenUpSymbol.Statement.SyntaxNode); var model = this.AnalysisContext.Compilation.GetSemanticModel( givenUpSymbol.Statement.SyntaxNode.SyntaxTree); this.AnalyzeOwnershipInControlFlowGraph(givenUpSymbol, machine, model, trace); } } }
/// <summary> /// Checks the states of each machine and report warnings if /// any state is declared as generic. /// </summary> /// <param name="machines">StateMachines</param> private void CheckStates(ISet <StateMachine> machines) { foreach (var machine in machines) { foreach (var state in machine.MachineStates) { if (state.Declaration.Arity > 0) { TraceInfo trace = new TraceInfo(); trace.AddErrorTrace(state.Declaration.Identifier); AnalysisErrorReporter.Report(trace, $"State '{state.Name}' was" + $" declared as generic, which is not allowed by P#."); } } } }
/// <summary> /// Analyzes the ownership of the given-up symbol in the expression. /// </summary> private void AnalyzeOwnershipInExpression(GivenUpOwnershipSymbol givenUpSymbol, ExpressionSyntax expr, Statement statement, SemanticModel model, TraceInfo trace) { if (expr is MemberAccessExpressionSyntax) { var identifier = AnalysisContext.GetRootIdentifier(expr); ISymbol symbol = model.GetSymbolInfo(identifier).Symbol; if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(symbol, givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement)) { TraceInfo newTrace = new TraceInfo(); newTrace.Merge(trace); newTrace.AddErrorTrace(statement.SyntaxNode); this.ErrorReporter.ReportGivenUpOwnershipAccess(newTrace); } } }
/// <summary> /// Analyzes the given-up ownership of fields in the expression. /// </summary> private void AnalyzeGivingUpFieldOwnership(GivenUpOwnershipSymbol givenUpSymbol, ISymbol symbol, Statement statement, StateMachine machine, TraceInfo trace) { if (!statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(symbol, givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement)) { return; } if (symbol.Kind == SymbolKind.Field && this.IsFieldAccessedInSuccessor(symbol as IFieldSymbol, statement.Summary, machine)) { TraceInfo newTrace = new TraceInfo(); newTrace.Merge(trace); newTrace.AddErrorTrace(statement.SyntaxNode); this.ErrorReporter.ReportGivenUpFieldOwnershipError(newTrace, symbol); } }
/// <summary> /// Prints the trace. /// </summary> /// <param name="trace">TraceInfo</param> private void PrintTrace(TraceInfo trace) { for (int idx = trace.ErrorTrace.Count - 1; idx >= 0; idx--) { if (idx == 0) { this.Logger.WriteLine(" --- Source of giving up ownership ---"); this.Logger.Write(" at '{0}' ", trace.ErrorTrace[idx].Expression); this.Logger.Write("in {0}:", trace.ErrorTrace[idx].File); this.Logger.WriteLine("line {0}", trace.ErrorTrace[idx].Line); } else { this.Logger.Write(" at '{0}' ", trace.ErrorTrace[idx].Expression); this.Logger.Write("in {0}:", trace.ErrorTrace[idx].File); this.Logger.WriteLine("line {0}", trace.ErrorTrace[idx].Line); } } }
/// <summary> /// Reports assignment of given up ownership to a machine field. /// </summary> internal void ReportGivenUpOwnershipFieldAssignment(TraceInfo trace, ISymbol fieldSymbol) { string message; if (trace.State is null) { message = string.Format(CultureInfo.InvariantCulture, "Method '{0}' of machine '{1}' assigns '{2}' to field '{3}' after giving up its ownership.", trace.Method, trace.Machine, trace.Payload, fieldSymbol); } else { message = string.Format(CultureInfo.InvariantCulture, "Method '{0}' in state '{1}' of machine '{2}' assigns '{3}' to field '{4}' after giving up its ownership.", trace.Method, trace.State, trace.Machine, trace.Payload, fieldSymbol); } this.ReportErrorTrace(trace, message); }
/// <summary> /// Reports sending data with a given up ownership. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="argSymbol">ISymbol</param> internal void ReportGivenUpOwnershipSending(TraceInfo trace, ISymbol argSymbol) { string message; if (trace.State == null) { message = IO.Utilities.Format("Method '{0}' of machine '{1}' sends '{2}', " + "the ownership of which has already been given up.", trace.Method, trace.Machine, argSymbol); } else { message = IO.Utilities.Format("Method '{0}' in state '{1}' of machine '{2}' " + "sends '{3}', the ownership of which has already been given up.", trace.Method, trace.State, trace.Machine, argSymbol); } this.ReportErrorTrace(trace, message); }
/// <summary> /// Reports sending data with a given up ownership. /// </summary> internal void ReportGivenUpOwnershipSending(TraceInfo trace, ISymbol argSymbol) { string message; if (trace.State is null) { message = string.Format(CultureInfo.InvariantCulture, "Method '{0}' of machine '{1}' sends '{2}', the ownership of which has already been given up.", trace.Method, trace.Machine, argSymbol); } else { message = string.Format(CultureInfo.InvariantCulture, "Method '{0}' in state '{1}' of machine '{2}' sends '{3}', the ownership of which has already been given up.", trace.Method, trace.State, trace.Machine, argSymbol); } this.ReportErrorTrace(trace, message); }
/// <summary> /// Reports calling a method with unavailable source code, /// thus cannot be further analyzed. /// </summary> internal void ReportExternalInvocation(TraceInfo trace) { string message; if (trace.State is null) { message = string.Format(CultureInfo.InvariantCulture, "Method '{0}' of machine '{1}' calls a method with unavailable source code, which might be a source of errors.", trace.Method, trace.Machine); } else { message = string.Format(CultureInfo.InvariantCulture, "Method '{0}' in state '{1}' of machine '{2}' calls a method with unavailable source code, which might be a source of errors.", trace.Method, trace.State, trace.Machine); } this.ReportWarningTrace(trace, message); }
/// <summary> /// Prints the trace. /// </summary> /// <param name="trace">TraceInfo</param> private static void PrintTrace(TraceInfo trace) { for (int idx = trace.ErrorTrace.Count - 1; idx >= 0; idx--) { if (idx == 0) { IO.PrintLine(" --- Source of giving up ownership ---"); IO.Print(" at '{0}' ", trace.ErrorTrace[idx].Expression); IO.Print("in {0}:", trace.ErrorTrace[idx].File); IO.PrintLine("line {0}", trace.ErrorTrace[idx].Line); } else { IO.Print(" at '{0}' ", trace.ErrorTrace[idx].Expression); IO.Print("in {0}:", trace.ErrorTrace[idx].File); IO.PrintLine("line {0}", trace.ErrorTrace[idx].Line); } } }
/// <summary> /// Reports a given up field ownership error. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="fieldSymbol">ISymbol</param> internal void ReportGivenUpFieldOwnershipError(TraceInfo trace, ISymbol fieldSymbol) { string message; if (trace.State == null) { message = IO.Utilities.Format("Method '{0}' of machine '{1}' sends '{2}', " + "which contains data from field '{3}'.", trace.Method, trace.Machine, trace.Payload, fieldSymbol); } else { message = IO.Utilities.Format("Method '{0}' in state '{1}' of machine '{2}' " + "sends '{3}', which contains data from field '{4}'.", trace.Method, trace.State, trace.Machine, trace.Payload, fieldSymbol); } this.ReportErrorTrace(trace, message); }
/// <summary> /// Reports assignment of given up ownership to a machine field. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="fieldSymbol">ISymbol</param> internal void ReportGivenUpOwnershipFieldAssignment(TraceInfo trace, ISymbol fieldSymbol) { string message; if (trace.State == null) { message = IO.Utilities.Format("Method '{0}' of machine '{1}' assigns '{2}' " + "to field '{3}' after giving up its ownership.", trace.Method, trace.Machine, trace.Payload, fieldSymbol); } else { message = IO.Utilities.Format("Method '{0}' in state '{1}' of machine '{2}' " + "assigns '{3}' to field '{4}' after giving up its ownership.", trace.Method, trace.State, trace.Machine, trace.Payload, fieldSymbol); } this.ReportErrorTrace(trace, message); }
/// <summary> /// Reports calling a virtual method with unknown overrider, /// thus cannot be further analyzed. /// </summary> internal void ReportUnknownVirtualCall(TraceInfo trace) { string message; if (trace.State is null) { message = string.Format(CultureInfo.InvariantCulture, "Method '{0}' of machine '{1}' calls a virtual method that cannot be further analyzed.", trace.Method, trace.Machine); } else { message = string.Format(CultureInfo.InvariantCulture, "Method '{0}' in state '{1}' of machine '{2}' calls a virtual method that cannot be further analyzed.", trace.Method, trace.State, trace.Machine); } this.ReportWarningTrace(trace, message); }
/// <summary> /// Reports calling a virtual method with unknown overrider, /// thus cannot be further analyzed. /// </summary> /// <param name="trace">TraceInfo</param> internal void ReportUnknownVirtualCall(TraceInfo trace) { string message; if (trace.State == null) { message = IO.Utilities.Format("Method '{0}' of machine '{1}' calls " + "a virtual method that cannot be further analyzed.", trace.Method, trace.Machine); } else { message = IO.Utilities.Format("Method '{0}' in state '{1}' of machine '{2}' " + "calls a virtual method that cannot be further analyzed.", trace.Method, trace.State, trace.Machine); } this.ReportWarningTrace(trace, message); }
/// <summary> /// Reports an access of an object with given-up ownership. /// </summary> /// <param name="trace">TraceInfo</param> internal void ReportGivenUpOwnershipAccess(TraceInfo trace) { string message; if (trace.State == null) { message = IO.Utilities.Format("Method '{0}' of machine '{1}' " + "accesses '{2}' after giving up its ownership.", trace.Method, trace.Machine, trace.Payload); } else { message = IO.Utilities.Format("Method '{0}' in state '{1}' of machine " + "'{2}' accesses '{3}' after giving up its ownership.", trace.Method, trace.State, trace.Machine, trace.Payload); } this.ReportErrorTrace(trace, message, true); }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the control-flow graph. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected override void AnalyzeOwnershipInControlFlowGraph(GivenUpOwnershipSymbol givenUpSymbol, StateMachine machine, SemanticModel model, TraceInfo trace) { var queue = new Queue<IControlFlowNode>(); queue.Enqueue(givenUpSymbol.Statement.ControlFlowNode); var visitedNodes = new HashSet<IControlFlowNode>(); visitedNodes.Add(givenUpSymbol.Statement.ControlFlowNode); bool repeatGivesUpNode = false; while (queue.Count > 0) { IControlFlowNode node = queue.Dequeue(); var statements = new List<Statement>(); if (!repeatGivesUpNode && node.Equals(givenUpSymbol.Statement.ControlFlowNode)) { statements.AddRange(node.Statements.SkipWhile( val => !val.Equals(givenUpSymbol.Statement))); } else if (repeatGivesUpNode && node.Equals(givenUpSymbol.Statement.ControlFlowNode)) { statements.AddRange(node.Statements.TakeWhile( val => !val.Equals(givenUpSymbol.Statement))); statements.Add(givenUpSymbol.Statement); } else { statements.AddRange(node.Statements); } foreach (var statement in statements) { base.AnalyzeOwnershipInStatement(givenUpSymbol, statement, machine, model, trace); } foreach (var successor in node.ISuccessors) { if (!repeatGivesUpNode && successor.Equals(givenUpSymbol.Statement.ControlFlowNode)) { repeatGivesUpNode = true; visitedNodes.Remove(givenUpSymbol.Statement.ControlFlowNode); } if (!visitedNodes.Contains(successor)) { queue.Enqueue(successor); visitedNodes.Add(successor); } } } }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the assignment expression. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="assignment">AssignmentExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected abstract void AnalyzeOwnershipInAssignment(GivenUpOwnershipSymbol givenUpSymbol, AssignmentExpressionSyntax assignment, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace);
/// <summary> /// Analyzes the method summaries of the machine to check if /// each summary respects given-up ownerships. /// </summary> /// <param name="machine">StateMachine</param> private void AnalyzeMethodSummariesInMachine(StateMachine machine) { foreach (var summary in machine.MethodSummaries.Values) { foreach (var givenUpSymbol in summary.GetSymbolsWithGivenUpOwnership()) { TraceInfo trace = new TraceInfo(summary.Method, machine, null, givenUpSymbol.ContainingSymbol); trace.AddErrorTrace(givenUpSymbol.Statement.SyntaxNode); var model = this.AnalysisContext.Compilation.GetSemanticModel( givenUpSymbol.Statement.SyntaxNode.SyntaxTree); this.AnalyzeOwnershipInControlFlowGraph(givenUpSymbol, machine, model, trace); } } }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the control-flow graph node. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected void AnalyzeOwnershipInStatement(GivenUpOwnershipSymbol givenUpSymbol, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { var localDecl = statement.SyntaxNode.DescendantNodesAndSelf(). OfType<LocalDeclarationStatementSyntax>().FirstOrDefault(); var expr = statement.SyntaxNode.DescendantNodesAndSelf(). OfType<ExpressionStatementSyntax>().FirstOrDefault(); if (localDecl != null) { var varDecl = localDecl.Declaration; this.AnalyzeOwnershipInLocalDeclaration(givenUpSymbol, varDecl, statement, machine, model, trace); } else if (expr != null) { if (expr.Expression is AssignmentExpressionSyntax) { var assignment = expr.Expression as AssignmentExpressionSyntax; this.AnalyzeOwnershipInAssignment(givenUpSymbol, assignment, statement, machine, model, trace); } else if (expr.Expression is InvocationExpressionSyntax || expr.Expression is ObjectCreationExpressionSyntax) { trace.InsertCall(statement.Summary.Method, expr.Expression); this.AnalyzeOwnershipInCall(givenUpSymbol, expr.Expression, statement, machine, model, trace); } } }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the variable declaration. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="varDecl">VariableDeclarationSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected abstract void AnalyzeOwnershipInLocalDeclaration(GivenUpOwnershipSymbol givenUpSymbol, VariableDeclarationSyntax varDecl, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace);
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the gives-up operation. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="call">Gives-up call</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected abstract void AnalyzeOwnershipInGivesUpCall(GivenUpOwnershipSymbol givenUpSymbol, InvocationExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace);
/// <summary> /// Reports sending data with a given up ownership. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="argSymbol">ISymbol</param> internal static void ReportGivenUpOwnershipSending(TraceInfo trace, ISymbol argSymbol) { string message; if (trace.State == null) { message = IO.Format("Method '{0}' of machine '{1}' sends '{2}', " + "the ownership of which has already been given up.", trace.Method, trace.Machine, argSymbol); } else { message = IO.Format("Method '{0}' in state '{1}' of machine '{2}' " + "sends '{3}', the ownership of which has already been given up.", trace.Method, trace.State, trace.Machine, argSymbol); } ReportErrorTrace(trace, message); }
/// <summary> /// Reports an error to the user. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="message">Message</param> /// <param name="allowMultiple">Allow multiple messages</param> private static void ReportErrorTrace(TraceInfo trace, string message, bool allowMultiple = false) { if (!allowMultiple && ReportedMessages.Contains(message)) { return; } Report(message); PrintTrace(trace); ReportedMessages.Add(message); }
/// <summary> /// Reports calling a virtual method with unknown overrider, /// thus cannot be further analyzed. /// </summary> /// <param name="trace">TraceInfo</param> internal static void ReportUnknownVirtualCall(TraceInfo trace) { string message; if (trace.State == null) { message = IO.Format("Method '{0}' of machine '{1}' calls " + "a virtual method that cannot be further analyzed.", trace.Method, trace.Machine); } else { message = IO.Format("Method '{0}' in state '{1}' of machine '{2}' " + "calls a virtual method that cannot be further analyzed.", trace.Method, trace.State, trace.Machine); } ReportWarningTrace(trace, message); }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the candidate callee. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="calleeSummary">MethodSummary</param> /// <param name="call">ExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected override void AnalyzeOwnershipInCandidateCallee(GivenUpOwnershipSymbol givenUpSymbol, MethodSummary calleeSummary, ExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { if (statement.Equals(givenUpSymbol.Statement) && !statement.ControlFlowNode.IsSuccessorOf( givenUpSymbol.Statement.ControlFlowNode)) { return; } var invocation = call as InvocationExpressionSyntax; if (invocation != null) { this.AnalyzeOwnershipInExpression(givenUpSymbol, invocation.Expression, statement, machine, model, trace); } ArgumentListSyntax argumentList = base.AnalysisContext.GetArgumentList(call); if (argumentList != null) { for (int idx = 0; idx < argumentList.Arguments.Count; idx++) { var argType = model.GetTypeInfo(argumentList.Arguments[idx].Expression).Type; if (base.AnalysisContext.IsTypePassedByValueOrImmutable(argType)) { continue; } var argIdentifier = base.AnalysisContext.GetRootIdentifier( argumentList.Arguments[idx].Expression); ISymbol argSymbol = model.GetSymbolInfo(argIdentifier).Symbol; if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(argSymbol, givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement)) { if (calleeSummary.SideEffectsInfo.ParameterAccesses.ContainsKey(idx)) { foreach (var access in calleeSummary.SideEffectsInfo.ParameterAccesses[idx]) { TraceInfo newTrace = new TraceInfo(); newTrace.Merge(trace); newTrace.AddErrorTrace(access.SyntaxNode); AnalysisErrorReporter.ReportGivenUpOwnershipAccess(newTrace); } } var fieldSymbols = calleeSummary.SideEffectsInfo.FieldFlowParamIndexes.Where( v => v.Value.Contains(idx)).Select(v => v.Key); foreach (var fieldSymbol in fieldSymbols) { if (base.IsFieldAccessedInSuccessor(fieldSymbol, statement.Summary, machine)) { AnalysisErrorReporter.ReportGivenUpOwnershipFieldAssignment(trace, fieldSymbol); } } if (calleeSummary.SideEffectsInfo.GivesUpOwnershipParamIndexes.Contains(idx)) { AnalysisErrorReporter.ReportGivenUpOwnershipSending(trace, argSymbol); } } } } foreach (var fieldAccess in calleeSummary.SideEffectsInfo.FieldAccesses) { foreach (var access in fieldAccess.Value) { if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(givenUpSymbol.ContainingSymbol, fieldAccess.Key, givenUpSymbol.Statement, statement)) { TraceInfo newTrace = new TraceInfo(); newTrace.Merge(trace); newTrace.AddErrorTrace(access.SyntaxNode); AnalysisErrorReporter.ReportGivenUpOwnershipFieldAccess(newTrace, fieldAccess.Key); } } } }
/// <summary> /// Reports an access of a field that is alias of /// an object with given-up ownership. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="fieldSymbol">ISymbol</param> internal static void ReportGivenUpOwnershipFieldAccess(TraceInfo trace, IFieldSymbol fieldSymbol) { string message; if (trace.State == null) { message = IO.Format("Method '{0}' of machine '{1}' accesses " + "'{2}', via field '{3}', after giving up its ownership.", trace.Method, trace.Machine, trace.Payload, fieldSymbol); } else { message = IO.Format("Method '{0}' in state '{1}' of machine '{2}' " + "accesses '{3}', via field '{4}', after giving up its ownership.", trace.Method, trace.State, trace.Machine, trace.Payload, fieldSymbol); } ReportErrorTrace(trace, message, true); }
/// <summary> /// Reports calling a method with unavailable source code, /// thus cannot be further analyzed. /// </summary> /// <param name="trace">TraceInfo</param> internal static void ReportExternalInvocation(TraceInfo trace) { string message; if (trace.State == null) { message = IO.Format("Method '{0}' of machine '{1}' calls " + "a method with unavailable source code, which might " + "be a source of errors.", trace.Method, trace.Machine); } else { message = IO.Format("Method '{0}' in state '{1}' of machine " + "'{2}' calls a method with unavailable source code, which " + "might be a source of errors.", trace.Method, trace.State, trace.Machine); } ReportWarningTrace(trace, message); }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the candidate callee. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="calleeSummary">MethodSummary</param> /// <param name="call">ExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected override void AnalyzeOwnershipInCandidateCallee(GivenUpOwnershipSymbol givenUpSymbol, MethodSummary calleeSummary, ExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { ArgumentListSyntax argumentList = base.AnalysisContext.GetArgumentList(call); if (argumentList == null) { return; } for (int idx = 0; idx < argumentList.Arguments.Count; idx++) { var argIdentifier = base.AnalysisContext.GetRootIdentifier( argumentList.Arguments[idx].Expression); if (argIdentifier == null) { continue; } ISymbol argSymbol = model.GetSymbolInfo(argIdentifier).Symbol; if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(argSymbol, givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement)) { if (calleeSummary.SideEffectsInfo.FieldFlowParamIndexes.Any(v => v.Value.Contains(idx) && base.IsFieldAccessedInSuccessor(v.Key, statement.Summary, machine))) { AnalysisErrorReporter.ReportGivenUpFieldOwnershipError(trace, argSymbol); } } } }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the variable declaration. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="varDecl">VariableDeclarationSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected override void AnalyzeOwnershipInLocalDeclaration(GivenUpOwnershipSymbol givenUpSymbol, VariableDeclarationSyntax varDecl, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { foreach (var variable in varDecl.Variables.Where(v => v.Initializer != null)) { var expr = variable.Initializer.Value; if (expr is IdentifierNameSyntax || expr is MemberAccessExpressionSyntax) { this.AnalyzeOwnershipInExpression(givenUpSymbol, expr, statement, machine, model, trace); } else if (expr is InvocationExpressionSyntax || expr is ObjectCreationExpressionSyntax) { trace.InsertCall(statement.Summary.Method, expr); base.AnalyzeOwnershipInCall(givenUpSymbol, expr, statement, machine, model, trace); } } }
/// <summary> /// Reports a given up field ownership error. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="fieldSymbol">ISymbol</param> internal static void ReportGivenUpFieldOwnershipError(TraceInfo trace, ISymbol fieldSymbol) { string message; if (trace.State == null) { message = IO.Format("Method '{0}' of machine '{1}' sends '{2}', " + "which contains data from field '{3}'.", trace.Method, trace.Machine, trace.Payload, fieldSymbol); } else { message = IO.Format("Method '{0}' in state '{1}' of machine '{2}' " + "sends '{3}', which contains data from field '{4}'.", trace.Method, trace.State, trace.Machine, trace.Payload, fieldSymbol); } ReportErrorTrace(trace, message); }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the gives-up operation. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="call">Gives-up call</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected override void AnalyzeOwnershipInGivesUpCall(GivenUpOwnershipSymbol givenUpSymbol, InvocationExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { if (statement.Equals(givenUpSymbol.Statement) && !statement.ControlFlowNode.IsSuccessorOf( givenUpSymbol.Statement.ControlFlowNode)) { return; } var opSymbol = model.GetSymbolInfo(call).Symbol; if ((!opSymbol.Name.Equals("Send") && !opSymbol.Name.Equals("CreateMachine")) || (opSymbol.Name.Equals("CreateMachine") && call.ArgumentList.Arguments.Count != 2)) { return; } ExpressionSyntax argExpr = call.ArgumentList.Arguments[1].Expression; var arguments = new List<ExpressionSyntax>(); if (argExpr is ObjectCreationExpressionSyntax) { var objCreation = argExpr as ObjectCreationExpressionSyntax; foreach (var arg in objCreation.ArgumentList.Arguments) { arguments.Add(arg.Expression); } } else if (argExpr is BinaryExpressionSyntax && argExpr.IsKind(SyntaxKind.AsExpression)) { var binExpr = argExpr as BinaryExpressionSyntax; if (binExpr.Left is IdentifierNameSyntax || binExpr.Left is MemberAccessExpressionSyntax) { arguments.Add(binExpr.Left); } else if (binExpr.Left is InvocationExpressionSyntax) { var invocation = binExpr.Left as InvocationExpressionSyntax; for (int i = 1; i < invocation.ArgumentList.Arguments.Count; i++) { arguments.Add(invocation.ArgumentList.Arguments[i].Expression); } } } else if (argExpr is IdentifierNameSyntax || argExpr is MemberAccessExpressionSyntax) { arguments.Add(argExpr); } var extractedArgs = base.ExtractArguments(arguments); foreach (var arg in extractedArgs) { IdentifierNameSyntax argIdentifier = base.AnalysisContext.GetRootIdentifier(arg); ITypeSymbol argType = model.GetTypeInfo(argIdentifier).Type; if (base.AnalysisContext.IsTypePassedByValueOrImmutable(argType)) { continue; } ISymbol argSymbol = model.GetSymbolInfo(argIdentifier).Symbol; if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(argSymbol, givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement)) { AnalysisErrorReporter.ReportGivenUpOwnershipSending(trace, argSymbol); return; } } }
/// <summary> /// Checks the methods of each machine and report warnings if /// any method is directly accessed by anything else than the /// P# runtime. /// </summary> /// <param name="machines">StateMachines</param> private void CheckMethods(ISet<StateMachine> machines) { foreach (var machine in machines) { foreach (var method in machine.Declaration.ChildNodes().OfType<MethodDeclarationSyntax>()) { if (method.Modifiers.Any(SyntaxKind.PublicKeyword)) { TraceInfo trace = new TraceInfo(); trace.AddErrorTrace(method.Identifier); AnalysisErrorReporter.ReportWarning(trace, "Method '{0}' of machine '{1}' " + "is declared as 'public'.", method.Identifier.ValueText, machine.Name); } else if (method.Modifiers.Any(SyntaxKind.InternalKeyword)) { TraceInfo trace = new TraceInfo(); trace.AddErrorTrace(method.Identifier); AnalysisErrorReporter.ReportWarning(trace, "Method '{0}' of machine '{1}' " + "is declared as 'internal'.", method.Identifier.ValueText, machine.Name); } } } }
/// <summary> /// Checks the fields of each machine and report warnings if /// any field is not private or protected. /// </summary> /// <param name="machines">StateMachines</param> private void CheckFields(ISet<StateMachine> machines) { foreach (var machine in machines) { foreach (var field in machine.Declaration.ChildNodes().OfType<FieldDeclarationSyntax>()) { if (field.Modifiers.Any(SyntaxKind.PublicKeyword)) { TraceInfo trace = new TraceInfo(); trace.AddErrorTrace(field); AnalysisErrorReporter.ReportWarning(trace, "Field '{0}' of machine '{1}' is " + "declared as 'public'.", field.Declaration.ToString(), machine.Name); } else if (field.Modifiers.Any(SyntaxKind.InternalKeyword)) { TraceInfo trace = new TraceInfo(); trace.AddErrorTrace(field); AnalysisErrorReporter.ReportWarning(trace, "Field '{0}' of machine '{1}' is " + "declared as 'internal'.", field.Declaration.ToString(), machine.Name); } } } }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the call. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="call">ExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> /// <returns>Set of return symbols</returns> protected HashSet<ISymbol> AnalyzeOwnershipInCall(GivenUpOwnershipSymbol givenUpSymbol, ExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { var potentialReturnSymbols = new HashSet<ISymbol>(); var invocation = call as InvocationExpressionSyntax; var objCreation = call as ObjectCreationExpressionSyntax; if ((invocation == null && objCreation == null)) { return potentialReturnSymbols; } TraceInfo callTrace = new TraceInfo(); callTrace.Merge(trace); callTrace.AddErrorTrace(call); var callSymbol = model.GetSymbolInfo(call).Symbol; if (callSymbol == null) { AnalysisErrorReporter.ReportExternalInvocation(callTrace); return potentialReturnSymbols; } if (callSymbol.ContainingType.ToString().Equals("Microsoft.PSharp.Machine")) { this.AnalyzeOwnershipInGivesUpCall(givenUpSymbol, invocation, statement, machine, model, callTrace); return potentialReturnSymbols; } if (SymbolFinder.FindSourceDefinitionAsync(callSymbol, this.AnalysisContext.Solution).Result == null) { AnalysisErrorReporter.ReportExternalInvocation(callTrace); return potentialReturnSymbols; } var candidateSummaries = MethodSummary.GetCachedSummaries(callSymbol, statement); foreach (var candidateSummary in candidateSummaries) { this.AnalyzeOwnershipInCandidateCallee(givenUpSymbol, candidateSummary, call, statement, machine, model, callTrace); if (invocation != null) { var resolvedReturnSymbols = candidateSummary.GetResolvedReturnSymbols(invocation, model); foreach (var resolvedReturnSymbol in resolvedReturnSymbols) { potentialReturnSymbols.Add(resolvedReturnSymbol); } } } return potentialReturnSymbols; }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the expression. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="expr">ExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> private void AnalyzeOwnershipInExpression(GivenUpOwnershipSymbol givenUpSymbol, ExpressionSyntax expr, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace) { if (expr is MemberAccessExpressionSyntax) { var identifier = base.AnalysisContext.GetRootIdentifier(expr); ISymbol symbol = model.GetSymbolInfo(identifier).Symbol; if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(symbol, givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement)) { TraceInfo newTrace = new TraceInfo(); newTrace.Merge(trace); newTrace.AddErrorTrace(statement.SyntaxNode); AnalysisErrorReporter.ReportGivenUpOwnershipAccess(newTrace); } } }
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the candidate callee. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="calleeSummary">MethodSummary</param> /// <param name="call">ExpressionSyntax</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected abstract void AnalyzeOwnershipInCandidateCallee(GivenUpOwnershipSymbol givenUpSymbol, MethodSummary calleeSummary, ExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace);
/// <summary> /// Analyzes the ownership of the given-up symbol /// in the control-flow graph. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="machine">StateMachine</param> /// <param name="model">SemanticModel</param> /// <param name="trace">TraceInfo</param> protected abstract void AnalyzeOwnershipInControlFlowGraph(GivenUpOwnershipSymbol givenUpSymbol, StateMachine machine, SemanticModel model, TraceInfo trace);
/// <summary> /// Reports assignment of given up ownership to a machine field. /// </summary> /// <param name="trace">TraceInfo</param> /// <param name="fieldSymbol">ISymbol</param> internal static void ReportGivenUpOwnershipFieldAssignment(TraceInfo trace, ISymbol fieldSymbol) { string message; if (trace.State == null) { message = IO.Format("Method '{0}' of machine '{1}' assigns '{2}' " + "to field '{3}' after giving up its ownership.", trace.Method, trace.Machine, trace.Payload, fieldSymbol); } else { message = IO.Format("Method '{0}' in state '{1}' of machine '{2}' " + "assigns '{3}' to field '{4}' after giving up its ownership.", trace.Method, trace.State, trace.Machine, trace.Payload, fieldSymbol); } ReportErrorTrace(trace, message); }
/// <summary> /// Merges the given trace to the current trace. /// </summary> /// <param name="traceInfo">TraceInfo</param> internal void Merge(TraceInfo traceInfo) { this.ErrorTrace.AddRange(traceInfo.ErrorTrace); this.CallTrace.AddRange(traceInfo.CallTrace); this.Method = traceInfo.Method; this.Machine = traceInfo.Machine; this.State = traceInfo.State; this.Payload = traceInfo.Payload; }