/// <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 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 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 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> /// Reports use of external asynchrony. /// </summary> /// <param name="log">Log</param> internal static void ReportExternalAsynchronyUsage(Log log) { AnalysisErrorReporter.ReportGenericError(log, "Machine '{0}' is trying to use non-P# asynchronous operations. " + "This can lead to data races and is *strictly* not allowed.", log.Machine); Environment.Exit(1); }
/// <summary> /// Checks the given machine for using non-P# related asynchrony. /// </summary> /// <param name="machine"></param> private static void CheckForExternalAsynchronyUseInMachine(ClassDeclarationSyntax machine) { if (machine.SyntaxTree.GetRoot().DescendantNodesAndSelf().Any(v => v.ToString().Contains("System.Threading"))) { Log log = new Log(null, machine, null, null); AnalysisErrorReporter.ReportExternalAsynchronyUsage(log); } }
/// <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)) { AnalysisErrorReporter.ReportGivenUpFieldOwnershipError(trace, givenUpSymbol.ContainingSymbol); } }
/// <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> /// Reports assignment of payload to a machine field. /// </summary> /// <param name="log">Log</param> internal static void ReportPayloadFieldAssignment(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportDataRaceSource(log, "Method '{0}' of machine '{1}' assigns the latest received " + "payload to a machine field.", log.Method, log.Machine); } else { AnalysisErrorReporter.ReportDataRaceSource(log, "Method '{0}' in state '{1}' of machine '{2}' assigns " + "the latest received payload to a machine field.", log.Method, log.State, log.Machine); } }
/// <summary> /// Reports calling a virtual method with unknown overrider, /// thus cannot be further analysed. /// </summary> /// <param name="log">Log</param> internal static void ReportUnknownVirtualCall(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportWarning(log, "Method '{0}' of machine '{1}' calls a virtual method that " + "cannot be further analysed.", log.Method, log.Machine); } else { AnalysisErrorReporter.ReportWarning(log, "Method '{0}' in state '{1}' of machine '{2}' calls a virtual " + "method that cannot be further analysed.", log.Method, log.State, log.Machine); } }
/// <summary> /// Reports a potendial data race. /// </summary> /// <param name="log">Log</param> internal static void ReportPotentialDataRace(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportOwnershipError(log, "Method '{0}' of machine '{1}' accesses '{2}' after " + "giving up its ownership.", log.Method, log.Machine, log.Payload); } else { AnalysisErrorReporter.ReportOwnershipError(log, "Method '{0}' in state '{1}' of machine '{2}' accesses " + "'{3}' after giving up its ownership.", log.Method, log.State, log.Machine, log.Payload); } }
/// <summary> /// Reports calling a method with unavailable source code, /// thus cannot be further analysed. /// </summary> /// <param name="log">Log</param> internal static void ReportUnknownInvocation(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportWarning(log, "Method '{0}' of machine '{1}' calls a method with unavailable " + "source code, which might be a source of errors.", log.Method, log.Machine); } else { AnalysisErrorReporter.ReportWarning(log, "Method '{0}' in state '{1}' of machine '{2}' calls a method " + "with unavailable source code, which might be a source of errors.", log.Method, log.State, log.Machine); } }
/// <summary> /// Reports sending data with a given up ownership. /// </summary> /// <param name="log">Log</param> internal static void ReportGivenUpOwnershipSending(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportOwnershipError(log, "Method '{0}' of machine '{1}' sends an event that contains " + "payload with already given up ownership.", log.Method, log.Machine); } else { AnalysisErrorReporter.ReportOwnershipError(log, "Method '{0}' in state '{1}' of machine '{2}' sends an event that " + "contains payload with already given up ownership.", log.Method, log.State, log.Machine); } }
/// <summary> /// Reports assignment of given up ownership to a machine field. /// </summary> /// <param name="log">Log</param> internal static void ReportGivenUpOwnershipFieldAssignment(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportOwnershipError(log, "Method '{0}' of machine '{1}' assigns '{2}' to " + "a machine field after giving up its ownership.", log.Method, log.Machine, log.Payload); } else { AnalysisErrorReporter.ReportOwnershipError(log, "Method '{0}' in state '{1}' of machine '{2}' assigns " + "'{3}' to a machine field after giving up its ownership.", log.Method, log.State, log.Machine, log.Payload); } }
/// <summary> /// Reports a given up field ownership error. /// </summary> /// <param name="log">Log</param> internal static void ReportGivenUpFieldOwnershipError(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportDataRaceSource(log, "Method '{0}' of machine '{1}' sends payload '{2}', which " + "contains data from a machine field.", log.Method, log.Machine, log.Payload); } else { AnalysisErrorReporter.ReportDataRaceSource(log, "Method '{0}' in state '{1}' of machine '{2}' sends payload " + "'{3}', which contains data from a machine field.", log.Method, log.State, log.Machine, log.Payload); } }
/// <summary> /// Reports a runtime only method access error. /// </summary> /// <param name="log">Log</param> internal static void ReportRuntimeOnlyMethodAccess(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportGenericError(log, "Method '{0}' of machine '{1}' is trying to access a P# " + "runtime only method.", log.Method, log.Machine); } else { AnalysisErrorReporter.ReportGenericError(log, "Method '{0}' in state {1} of machine '{2}' is trying to " + "access a P# runtime only method.", log.Method, log.State, log.Machine); } Environment.Exit(1); }
/// <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 given-up ownership of fields in the expression. /// </summary> /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param> /// <param name="symbol">Symbol</param> /// <param name="statement">Statement</param> /// <param name="machine">StateMachine</param> /// <param name="trace">TraceInfo</param> 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 && base.IsFieldAccessedInSuccessor(symbol as IFieldSymbol, statement.Summary, machine)) { TraceInfo newTrace = new TraceInfo(); newTrace.Merge(trace); newTrace.AddErrorTrace(statement.SyntaxNode); AnalysisErrorReporter.ReportGivenUpFieldOwnershipError(newTrace, symbol); } }
/// <summary> /// Reports an explicit state initialisation error. /// </summary> /// <param name="log">Log</param> internal static void ReportExplicitStateInitialisation(Log log) { if (log.State == null) { AnalysisErrorReporter.ReportGenericError(log, "Method '{0}' of machine '{1}' is trying to explicitly " + "initialize a machine state.", log.Method, log.Machine); } else { AnalysisErrorReporter.ReportGenericError(log, "Method '{0}' in state {1} of machine '{2}' is trying to " + "explicitly initialize a machine state.", log.Method, log.State, log.Machine); } Environment.Exit(1); }
/// <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 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> /// 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> /// Check the given statement for any missbehaviour. /// </summary> /// <param name="stmt">Statement</param> /// <param name="method">Method</param> /// <param name="machine">machine</param> /// <param name="state">state</param> private static void CheckStatement(StatementSyntax stmt, MethodDeclarationSyntax method, ClassDeclarationSyntax machine, ClassDeclarationSyntax state = null) { if (stmt is ExpressionStatementSyntax) { var exprStmt = stmt as ExpressionStatementSyntax; if (exprStmt.Expression is InvocationExpressionSyntax) { var invExprStmt = exprStmt.Expression as InvocationExpressionSyntax; if (invExprStmt.Expression is MemberAccessExpressionSyntax) { var callStmt = invExprStmt.Expression as MemberAccessExpressionSyntax; if (callStmt.Name.Identifier.ValueText.Equals("OnEntry") || callStmt.Name.Identifier.ValueText.Equals("OnExit") || callStmt.Name.Identifier.ValueText.Equals("DefineIgnoredEvents") || callStmt.Name.Identifier.ValueText.Equals("DefineDeferredEvents") || callStmt.Name.Identifier.ValueText.Equals("DefineGotoStateTransitions") || callStmt.Name.Identifier.ValueText.Equals("DefinePushStateTransitions") || callStmt.Name.Identifier.ValueText.Equals("DefineActionBindings")) { Log log = new Log(method, machine, state, null); log.AddTrace(callStmt.ToString(), callStmt.SyntaxTree.FilePath, callStmt.SyntaxTree. GetLineSpan(callStmt.Span).StartLinePosition.Line + 1); AnalysisErrorReporter.ReportRuntimeOnlyMethodAccess(log); } } } else if (exprStmt.Expression is BinaryExpressionSyntax) { var binExprStmt = exprStmt.Expression as BinaryExpressionSyntax; if (binExprStmt.Right is ObjectCreationExpressionSyntax) { var newObjStmt = binExprStmt.Right as ObjectCreationExpressionSyntax; if (SanityCheckingAnalysis.IsStateOfTheMachine(newObjStmt.Type.ToString(), machine)) { Log log = new Log(method, machine, state, null); log.AddTrace(newObjStmt.ToString(), newObjStmt.SyntaxTree.FilePath, newObjStmt.SyntaxTree. GetLineSpan(newObjStmt.Span).StartLinePosition.Line + 1); AnalysisErrorReporter.ReportExplicitStateInitialisation(log); } } } } else if (stmt is LocalDeclarationStatementSyntax) { var localDeclStmt = stmt as LocalDeclarationStatementSyntax; foreach (var variable in localDeclStmt.Declaration.Variables) { if (variable.Initializer != null && variable.Initializer.Value is ObjectCreationExpressionSyntax) { var newObjStmt = variable.Initializer.Value as ObjectCreationExpressionSyntax; if (SanityCheckingAnalysis.IsStateOfTheMachine(newObjStmt.Type.ToString(), machine)) { Log log = new Log(method, machine, state, null); log.AddTrace(newObjStmt.ToString(), newObjStmt.SyntaxTree.FilePath, newObjStmt.SyntaxTree. GetLineSpan(newObjStmt.Span).StartLinePosition.Line + 1); AnalysisErrorReporter.ReportExplicitStateInitialisation(log); } } } } else if (stmt is IfStatementSyntax) { var ifStmt = stmt as IfStatementSyntax; if (ifStmt.Statement is BlockSyntax) { var ifBlockStmt = ifStmt.Statement as BlockSyntax; foreach (var ibs in ifBlockStmt.Statements) { SanityCheckingAnalysis.CheckStatement(ibs, method, machine, state); } if (ifStmt.Else != null) { if (ifStmt.Else.Statement is IfStatementSyntax) { SanityCheckingAnalysis.CheckStatement(ifStmt.Else.Statement, method, machine, state); } else if (ifStmt.Else.Statement is BlockSyntax) { var elseBlockStmt = ifStmt.Else.Statement as BlockSyntax; foreach (var ebs in elseBlockStmt.Statements) { SanityCheckingAnalysis.CheckStatement(ebs, method, machine, state); } } } } else { SanityCheckingAnalysis.CheckStatement(ifStmt.Statement, method, machine, state); } } else if (stmt is ForStatementSyntax) { var forStmt = stmt as ForStatementSyntax; if (forStmt.Statement is BlockSyntax) { var forBlockStmt = forStmt.Statement as BlockSyntax; foreach (var fbs in forBlockStmt.Statements) { SanityCheckingAnalysis.CheckStatement(fbs, method, machine, state); } } else { SanityCheckingAnalysis.CheckStatement(forStmt.Statement, method, machine, state); } } else if (stmt is ForEachStatementSyntax) { var forEachStmt = stmt as ForEachStatementSyntax; if (forEachStmt.Statement is BlockSyntax) { var forEachBlockStmt = forEachStmt.Statement as BlockSyntax; foreach (var fbs in forEachBlockStmt.Statements) { SanityCheckingAnalysis.CheckStatement(fbs, method, machine, state); } } else { SanityCheckingAnalysis.CheckStatement(forEachStmt.Statement, method, machine, state); } } else if (stmt is WhileStatementSyntax) { var whileStmt = stmt as WhileStatementSyntax; if (whileStmt.Statement is BlockSyntax) { var whileBlockStmt = whileStmt.Statement as BlockSyntax; foreach (var wbs in whileBlockStmt.Statements) { SanityCheckingAnalysis.CheckStatement(wbs, method, machine, state); } } else { SanityCheckingAnalysis.CheckStatement(whileStmt.Statement, method, machine, state); } } else if (stmt is DoStatementSyntax) { var doStmt = stmt as DoStatementSyntax; if (doStmt.Statement is BlockSyntax) { var doBlockStmt = doStmt.Statement as BlockSyntax; foreach (var dbs in doBlockStmt.Statements) { SanityCheckingAnalysis.CheckStatement(dbs, method, machine, state); } } else { SanityCheckingAnalysis.CheckStatement(doStmt.Statement, method, machine, state); } } else if (stmt is SwitchStatementSyntax) { var switchStmt = stmt as SwitchStatementSyntax; foreach (var section in switchStmt.Sections) { foreach (var sbs in section.Statements) { SanityCheckingAnalysis.CheckStatement(sbs, method, machine, state); } } } else if (stmt is TryStatementSyntax) { var tryStmt = stmt as TryStatementSyntax; foreach (var tbs in tryStmt.Block.Statements) { SanityCheckingAnalysis.CheckStatement(tbs, method, machine, state); } foreach (var ctch in tryStmt.Catches) { foreach (var cbs in ctch.Block.Statements) { SanityCheckingAnalysis.CheckStatement(cbs, method, machine, state); } } if (tryStmt.Finally != null) { foreach (var tbs in tryStmt.Finally.Block.Statements) { SanityCheckingAnalysis.CheckStatement(tbs, method, machine, state); } } } else if (stmt is UsingStatementSyntax) { var usingStmt = stmt as UsingStatementSyntax; var usingBlockStmt = usingStmt.Statement as BlockSyntax; foreach (var ubs in usingBlockStmt.Statements) { SanityCheckingAnalysis.CheckStatement(ubs, method, machine, state); } } }