Ejemplo n.º 1
0
        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;
        }
Ejemplo n.º 2
0
        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);
        }