/// <summary> /// Checks the methods of each machine and report warnings if /// any method is directly accessed by anything else than the /// P# runtime. /// </summary> private static void CheckMethods() { foreach (var classDecl in AnalysisContext.Machines) { SanityCheckingAnalysis.CheckForExternalAsynchronyUseInMachine(classDecl); foreach (var nestedClass in classDecl.ChildNodes().OfType <ClassDeclarationSyntax>()) { if (nestedClass.BaseList == null || !nestedClass.BaseList.Types.Any(t => t.ToString().Equals("MachineState"))) { ErrorReporter.ReportAndExit("Class '{0}' is not a state of the machine '{1}' " + "and, thus, is not allowed to be declared inside the machine body.", nestedClass.Identifier.ValueText, classDecl.Identifier.ValueText); } foreach (var method in nestedClass.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (method.Modifiers.Any(SyntaxKind.AbstractKeyword)) { continue; } foreach (var stmt in method.Body.Statements) { SanityCheckingAnalysis.CheckStatement(stmt, method, classDecl, nestedClass); } } } foreach (var method in classDecl.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (method.Modifiers.Any(SyntaxKind.AbstractKeyword)) { continue; } foreach (var stmt in method.Body.Statements) { SanityCheckingAnalysis.CheckStatement(stmt, method, classDecl); } } } }
/// <summary> /// Runs the analysis. /// </summary> public static void Run() { SanityCheckingAnalysis.CheckMethods(); }
/// <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); } } }