public override void RewriteChildren(MethodDefinition methodDefinition) { var methodContract = contractProvider.GetMethodContractFor(methodDefinition); if (methodContract == null) { return; } var sourceMethodBody = methodDefinition.Body as ISourceMethodBody; if (sourceMethodBody == null) { return; } var newStatements = new List <IStatement>(); var existingStatements = new List <IStatement>(sourceMethodBody.Block.Statements); existingStatements = Rewrite(existingStatements); // keep the call to the base constructor at the top if (methodDefinition.IsConstructor && existingStatements.Count > 0) { newStatements.Add(existingStatements[0]); existingStatements.RemoveAt(0); } /* if the query returns a value, instead of copying the postconditions at the end of each * single return in the code, we assign the value at that point to a local variable and jump * to the beginning of the postcondition block. */ // add a new local variable to store the value at return LocalDeclarationStatement retLocal = null; if (TypeHelper.GetTypeName(methodDefinition.Type) != TypeHelper.GetTypeName(host.PlatformType.SystemVoid)) { retLocal = new LocalDeclarationStatement { LocalVariable = new LocalDefinition { Name = host.NameTable.GetNameFor("retLocal"), Type = methodDefinition.Type }, InitialValue = new CompileTimeConstant { Type = methodDefinition.Type, Value = null } }; newStatements.Add(retLocal); } // add the preconditions as assumes foreach (var precondition in methodContract.Preconditions) { var methodCall = new MethodCall { Arguments = new List <IExpression> { Rewrite(precondition.Condition), precondition.Description ?? new CompileTimeConstant { Type = host.PlatformType.SystemString, Value = "Precondition" } }, IsStaticCall = true, MethodToCall = AssumeReference, Type = systemVoid, Locations = new List <ILocation>(precondition.Locations) }; var es = new ExpressionStatement { Expression = methodCall }; newStatements.Add(es); } // Add the invariant as a precondition as well var typeContract = contractProvider.GetTypeContractFor(methodDefinition.ContainingTypeDefinition); if (typeContract != null) { foreach (var inv in typeContract.Invariants) { var methodCall = new MethodCall { Arguments = new List <IExpression> { Rewrite(inv.Condition), new CompileTimeConstant { Value = "Type invariant", Type = host.PlatformType.SystemString } }, IsStaticCall = true, MethodToCall = AssumeReference, Type = systemVoid, Locations = new List <ILocation>(inv.Locations) }; var es = new ExpressionStatement { Expression = methodCall }; newStatements.Add(es); } } // the dummy statement is going to indicate the beginning of the postcondition block var dummyPostconditionStatement = new LabeledStatement { Label = host.NameTable.GetNameFor("dummyPostconditionStatement"), Statement = new EmptyStatement() }; var retRewriter = new ReturnRewriter(host, dummyPostconditionStatement, retLocal); //replace (nested) ReturnStatements with the GoTo to a single return at the end newStatements.AddRange(existingStatements.Select(stmt => retRewriter.Rewrite(stmt))); // now, that all the existing statements were added it is time for the postcondition block newStatements.Add(dummyPostconditionStatement); // Add assume statements for each postcondition that predicates ONLY about parameters (ie. not about the instance) var contractDependencyAnalyzer = new CciContractDependenciesAnalyzer(contractProvider); foreach (var postcondition in methodContract.Postconditions) { if (contractDependencyAnalyzer.PredicatesAboutInstance(postcondition) || !contractDependencyAnalyzer.PredicatesAboutParameter(postcondition)) { continue; } var methodCall = new MethodCall { Arguments = new List <IExpression> { Rewrite(postcondition.Condition), new CompileTimeConstant { Type = host.PlatformType.SystemString, Value = "Conditions over parameters are assumed satisfiable" } }, IsStaticCall = true, MethodToCall = AssumeReference, Type = systemVoid, Locations = new List <ILocation>(postcondition.Locations) }; var es = new ExpressionStatement { Expression = methodCall }; newStatements.Add(es); } // the postcondition block. Add each postcondition as an assert foreach (var postcondition in methodContract.Postconditions) { var methodCall = new MethodCall { Arguments = new List <IExpression> { Rewrite(postcondition.Condition), postcondition.Description ?? new CompileTimeConstant { Type = host.PlatformType.SystemString, Value = "Postcondition" } }, IsStaticCall = true, MethodToCall = AssertReference, Type = systemVoid, Locations = new List <ILocation>(postcondition.Locations) }; var es = new ExpressionStatement { Expression = methodCall }; newStatements.Add(es); } // add the invariant as a postcondition as well if (typeContract != null) { foreach (var inv in typeContract.Invariants) { var methodCall = new MethodCall { Arguments = new List <IExpression> { Rewrite(inv.Condition), new CompileTimeConstant { Value = "Type invariant", Type = host.PlatformType.SystemString } }, IsStaticCall = true, MethodToCall = AssertReference, Type = systemVoid, Locations = new List <ILocation>(inv.Locations) }; var es = new ExpressionStatement { Expression = methodCall }; newStatements.Add(es); } } IReturnStatement returnStatement; if (TypeHelper.GetTypeName(methodDefinition.Type) != TypeHelper.GetTypeName(host.PlatformType.SystemVoid)) { // If the method is not void, the return statement have to include the local variable returnStatement = new ReturnStatement { Expression = new BoundExpression { Definition = retLocal.LocalVariable, Instance = null, Type = retLocal.LocalVariable.Type } }; } else { returnStatement = new ReturnStatement(); } newStatements.Add(returnStatement); var newSourceMethodBody = new SourceMethodBody(host, sourceLocationProvider) { Block = new BlockStatement { Statements = newStatements }, IsNormalized = false, LocalsAreZeroed = sourceMethodBody.LocalsAreZeroed, MethodDefinition = methodDefinition }; methodDefinition.Body = newSourceMethodBody; }
private MethodContract CreateQueryContract(State state, State target) { var contracts = new MethodContract(); // Source state invariant as a precondition var stateInv = Helper.GenerateStateInvariant(host, state); var preconditions = from condition in stateInv select new Precondition { Condition = condition, OriginalSource = new CciExpressionPrettyPrinter().PrintExpression(condition), Description = new CompileTimeConstant { Value = "Source state invariant", Type = host.PlatformType.SystemString } }; contracts.Preconditions.AddRange(preconditions); // Add a redundant postcondition for only those conditions that predicate ONLY about parameters and not the instance. // These postconditions will be translated as assumes in the ContractRewriter.cs var contractDependencyAnalyzer = new CciContractDependenciesAnalyzer(new ContractProvider(new ContractMethods(host), null)); foreach (var action in target.EnabledActions.Union(target.DisabledActions)) { if (action.Contract != null) { foreach (var pre in action.Contract.Preconditions) { if (contractDependencyAnalyzer.PredicatesAboutInstance(pre) || !contractDependencyAnalyzer.PredicatesAboutParameter(pre)) { continue; } var post = new Postcondition { Condition = pre.Condition, OriginalSource = new CciExpressionPrettyPrinter().PrintExpression(pre.Condition), Description = new CompileTimeConstant { Value = "Conditions over parameters are assumed satisfiable", Type = host.PlatformType.SystemString } }; contracts.Postconditions.Add(post); } } } // Negated target state invariant as a postcondition var targetInv = Helper.GenerateStateInvariant(host, target); IExpression joinedTargetInv = new LogicalNot { Type = host.PlatformType.SystemBoolean, Operand = Helper.JoinWithLogicalAnd(host, targetInv, true) }; var postcondition = new Postcondition { Condition = joinedTargetInv, OriginalSource = new CciExpressionPrettyPrinter().PrintExpression(joinedTargetInv), Description = new CompileTimeConstant { Value = "Negated target state invariant", Type = host.PlatformType.SystemString } }; contracts.Postconditions.Add(postcondition); return(contracts); }