Пример #1
0
 public RequiresList Apply(RequiresList reqs)
 {
     if (specializer != null)
     {
         specializer.CurrentMethod = method;
         specializer.CurrentType = method.DeclaringType;
         reqs = specializer.VisitRequiresList(reqs);
     }
     RequiresList result = this.VisitRequiresList(reqs);
     return result;
 }
Пример #2
0
            public void Visit(RequiresList requires)
            {
                if (requires == null) return;

                for (int i = 0; i < requires.Count; i++)
                {
                    this.Visit(requires[i]);
                }
            }
Пример #3
0
        /// <summary>
        /// Method replaces Requires to Assume in the MoveNext method of the async or iterator state machine.
        /// </summary>
        private void ReplaceRequiresWithAssumeInMoveNext(RequiresList origPreconditions, AssumeBlock originalContractPosition)
        {
            Contract.Assert(origPreconditions != null);

            if (originalContractPosition != null && originalContractPosition.Statements != null
                /*&& origPreconditions != null */&& origPreconditions.Count > 0)
            {
                var origStatements = originalContractPosition.Statements;
                foreach (var pre in origPreconditions)
                {
                    if (pre == null) continue;

                    var assume = new MethodCall(
                        new MemberBinding(null, this.contractNodes.AssumeMethod),
                        new ExpressionList(pre.Condition), NodeType.Call);

                    assume.SourceContext = pre.SourceContext;
                    var assumeStmt = new ExpressionStatement(assume);

                    assumeStmt.SourceContext = pre.SourceContext;
                    origStatements.Add(assumeStmt);
                }
            }
        }
Пример #4
0
        // Ensures:
        //  Preconditions != null
        //  && ForAll{Requires r in Preconditions;
        //              r.Condition is BlockExpression
        //              && r.Condition.Type == Void
        //              && IsClump(r.Condition.Block.Statements)
        //  Postconditions != null
        //  && ForAll{Ensures e in Posconditions;
        //              e.PostCondition is BlockExpression
        //              && e.PostCondition.Type == Void
        //              && IsClump(e.PostCondition.Block.Statements)
        //  (In addition, each Requires is a RequiresPlain when the contract
        //   call is Contract.Requires and is a RequiresOtherwise when the
        //   contract call is Critical.Requires. In the latter case, the
        //   ThrowException is filled in correctly.)
        //       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="method"></param>
        /// <param name="Preconditions"></param>
        /// <param name="Postconditions"></param>
        /// <param name="Validations"></param>
        /// <param name="contractInitializerBlock">used to store extra closure initializations from abbrevs and validators</param>
        public void CheapAndDirty(
            Method method,
            ref RequiresList Preconditions,
            ref EnsuresList Postconditions,
            ref RequiresList Validations,
            ref EnsuresList modelPostConditions,
            Block contractInitializerBlock,
            ref HelperMethods.StackDepthTracker dupStackTracker)
        {
            if (this.verbose)
            {
                Console.WriteLine("Method : " + method.FullName);
            }

            if (method == null || method.Body == null || method.Body.Statements == null ||
                method.Body.Statements.Count <= 0)
            {
                return;
            }

            Block methodBody = method.Body;
            int n = methodBody.Statements.Count;
            int beginning = 0;

            while (beginning < n && methodBody.Statements[beginning] is PreambleBlock)
            {
                beginning++;
            }

            int lastBlockContainingContract;
            int lastStatementContainingContract;

            bool anyContractCall = FindLastBlockWithContracts(methodBody.Statements, beginning,
                out lastBlockContainingContract, out lastStatementContainingContract);

            // Make sure any locals in the contracts are disjoint from the locals in the rest of the body

            // can use the same one throughout
            GatherLocals gatherLocals = new GatherLocals();

            SourceContext lastContractSourceContext = method.SourceContext;
            if (!anyContractCall)
            {
                if (this.verbose)
                {
                    Console.WriteLine("\tNo contracts found");
                }

                // still need to check for bad other contract calls in method body

                goto CheckBody;
            }

            Block lastBlock = methodBody.Statements[lastBlockContainingContract] as Block;
            lastContractSourceContext = lastBlock.SourceContext;

            // probably not a good context, what to do if one can't be found?
            if (lastBlock.Statements != null && 0 <= lastStatementContainingContract &&
                lastStatementContainingContract < lastBlock.Statements.Count)
            {
                lastContractSourceContext = lastBlock.Statements[lastStatementContainingContract].SourceContext;
            }

            // Make sure contract section is not in any try-catch region

            TrivialHashtable<int> block2Index = new TrivialHashtable<int>(methodBody.Statements.Count);
            for (int i = 0, nn = methodBody.Statements.Count; i < nn; i++)
            {
                if (methodBody.Statements[i] == null) continue;
                block2Index[methodBody.Statements[i].UniqueKey] = i;
            }
            // Check each exception handler and see if any overlap with the contract section
            for (int i = 0, nn = method.ExceptionHandlers == null ? 0 : method.ExceptionHandlers.Count; i < nn; i++)
            {
                ExceptionHandler eh = method.ExceptionHandlers[i];
                if (eh == null) continue;

                if (((int) block2Index[eh.BlockAfterTryEnd.UniqueKey]) < beginning ||
                    lastBlockContainingContract < ((int) block2Index[eh.TryStartBlock.UniqueKey]))
                {
                    continue; // can't overlap
                }

                this.HandleError(method, 1024, "Contract section within try block.", lastContractSourceContext);
                return;
            }

            // Extract <beginning,0> to <lastBlockContainingContract,lastStatmentContainingContract>
            StatementList contractClump = HelperMethods.ExtractClump(methodBody.Statements, beginning, 0,
                lastBlockContainingContract, lastStatementContainingContract);

            // Look for bad stuff

            BadStuff(method, contractClump, lastContractSourceContext);

            // Make sure that the entire contract section is closed.
            if (!CheckClump(method, gatherLocals, currentMethodSourceContext, new Block(contractClump)))
            {
                return;
            }

            // Checking that had the side effect of populating the hashtable, but now each contract will be individually visited.
            // That process needs to start with a fresh table.
            gatherLocals.Locals = new TrivialHashtable();

            Preconditions = new RequiresList();
            Postconditions = new EnsuresList();
            Validations = new RequiresList();
            modelPostConditions = new EnsuresList();

            if (!ExtractFromClump(
                contractClump, method, gatherLocals, Preconditions, Postconditions, Validations,
                modelPostConditions, lastContractSourceContext, method, contractInitializerBlock, ref dupStackTracker))
            {
                return;
            }

            CheckBody:

            // Check "real" method body for use of any locals used in contracts

            //      var checkMethodBody = new CheckForBadContractStuffInMethodBody(gatherLocals, this.CallErrorFound, method);
            var checkMethodBody = new CheckLocals(gatherLocals);
            checkMethodBody.Visit(methodBody);

            if (!this.fSharp && checkMethodBody.reUseOfExistingLocal != null)
            {
                SourceContext sc = lastContractSourceContext;

                this.HandleError(method, 1025,
                    "After contract block, found use of local variable '" +
                    checkMethodBody.reUseOfExistingLocal.Name.Name + "' defined in contract block", sc);
            }
        }
Пример #5
0
    // Instead of overriding VisitRequiresPlain or VisitRequiresOtherwise, just process the list.
    // Almost all of the code is the same for both plain and otherwise requires.
    // This could be done by overriding VisitRequires -- but would depend upon introducing
    // a VisitRequires method in StandardVisitor.
    public override RequiresList VisitRequiresList(RequiresList Requires){
      // add a default precondition here and not earlier in the pipeline so it doesn't confuse
      // the contract inheritance checks.
      // REVIEW: probably better to add it earlier and have a HasCompilerGeneratedSignature on it
      // so it can be ignored in the inheritance checks.
      bool addDefaultPrecondition = 
        this.currentMethod != null
        && !this.currentMethod.IsStatic
        && !this.currentMethod.IsAbstract
        && this.currentMethod.Body != null && this.currentMethod.Body.Statements != null
        && !(this.currentMethod.HasCompilerGeneratedSignature && !this.currentMethod.Name.Name.StartsWith("get_") && !this.currentMethod.Name.Name.StartsWith("set_"))
        && this.currentMethod.NodeType != NodeType.InstanceInitializer
        && this.currentMethod.NodeType != NodeType.StaticInitializer
        && (this.currentType != null && this.currentType.Contract != null && this.currentType.Contract.FramePropertyGetter != null)
        && this.currentMethod.GetAttribute(SystemTypes.NoDefaultContractAttribute) == null
        ;
      
      RequiresList newRequires = new RequiresList();

      if (addDefaultPrecondition){
        Method frameGetter = this.currentType.Contract.FramePropertyGetter;
        Method m = null;
        // We used to use "get_CanStartWriting" for non-virtual methods. But Rustan and I decided
        // that it should be fine to use the transitive one for all methods. It is more liberal
        // but still prevents re-entrance into a method in a frame that is exposed.
        m = SystemTypes.Guard.GetMethod(Identifier.For("get_CanStartWritingTransitively"), null);

        // default precondition is (as normalized IR):
        // requires this.get_FrameGuard().get_CanStartWriting(); if it is a non-virtual method
        // requires this.get_FrameGuard().get_CanStartWritingTransitively(); if it is a virtual method
        if (frameGetter != null && m != null){
          SourceContext sc = this.currentMethod.Name.SourceContext;
          MethodCall getFrameGuard = new MethodCall(new MemberBinding(this.currentThisParameter, frameGetter), null, NodeType.MethodCall, SystemTypes.Guard, sc);
          Requires r = new RequiresOtherwise(
            new MethodCall(
            new MemberBinding(getFrameGuard,m),
            null,
            NodeType.MethodCall,
            SystemTypes.Boolean),
            new Construct(new MemberBinding(null, SystemTypes.RequiresException.GetConstructor(SystemTypes.String)), new ExpressionList(new Literal("The target object of this call must be exposable.", SystemTypes.String)), SystemTypes.RequiresException)
            );
          r.SourceContext = sc;
          newRequires.Add(r);
        }
      }

      if ((this.currentMethod.IsPublic || this.currentMethod.IsFamilyOrAssembly) &&
        !(this.currentCompilation != null && this.currentCompilation.CompilerParameters != null &&
        ((CompilerOptions)this.currentCompilation.CompilerParameters).DisableNullParameterValidation)){
        ParameterList parameters = this.currentMethod.Parameters;
        for (int i = 0, n = parameters == null ? 0 : parameters.Count; i < n; i++){
          Parameter parameter = parameters[i];
          if (parameter != null && !parameter.IsOut && this.typeSystem.IsNonNullType(parameter.Type)){
            RequiresOtherwise r;
            Reference rtype = parameter.Type as Reference;
            if (rtype == null) {
              TypeNode parameterType = TypeNode.StripModifier(parameter.Type, SystemTypes.NonNullType);
              Expression e = null;
              if (this.useGenerics && (parameterType is TypeParameter || parameterType is ClassParameter)) {
                e = new BinaryExpression(parameter, new MemberBinding(null, parameterType), NodeType.Box, SystemTypes.Object, parameter.SourceContext);
              } else {
                e = new ParameterBinding(parameter, parameter.SourceContext);
              }
              r =
                new RequiresOtherwise(
                new BinaryExpression(e, new Literal(null, TypeNode.StripModifiers(parameter.Type)), NodeType.Ne, SystemTypes.Boolean, parameter.SourceContext),
                new Construct(new MemberBinding(null, SystemTypes.ArgumentNullException.GetConstructor(SystemTypes.String)), new ExpressionList(new Literal(parameter.Name.Name, SystemTypes.String)), SystemTypes.ArgumentNullException));
            }
            else {
              // have to perform deref
              r =
                new RequiresOtherwise(
                new BinaryExpression(new AddressDereference(new ParameterBinding(parameter, parameter.SourceContext), rtype.ElementType), new Literal(null, TypeNode.StripModifiers(rtype.ElementType)), NodeType.Ne, SystemTypes.Boolean, parameter.SourceContext),
                new Construct(new MemberBinding(null, SystemTypes.ArgumentNullException.GetConstructor(SystemTypes.String)), new ExpressionList(new Literal(parameter.Name.Name, SystemTypes.String)), SystemTypes.ArgumentNullException));
            }
            r.SourceContext = parameter.SourceContext;
            newRequires.Add(r);
          }
        }
      }

      for (int i = 0, n = Requires == null ? 0 : Requires.Count; i < n; i++){
        newRequires.Add(Requires[i]);
      }

      if (newRequires.Count == 0)
          return Requires;

      Block preConditionBlock = new Block(new StatementList());
      preConditionBlock.HasLocals = true;

      for (int i = 0, n = newRequires.Count; i < n; i++)
      {
        Requires r = newRequires[i];
        if (r == null) continue;
        if (r.Condition == null) continue;

        // Code generation for preconditions needs to be such that the
        // data flow analysis will "see" the consequences. If the value
        // of the precondition is assigned to a local, then the information
        // is lost.
        //
        // try {
        //   if re goto pre_i_holds;
        // }
        // catch { throw new ErrorDuringPreConditionEvaluation(...); }
        // throw new PreConditionException(...);
        // pre_i_holds: nop

        bool noAllocationAllowed = this.currentMethod.GetAttribute(SystemTypes.BartokNoHeapAllocationAttribute) != null;
        Local exceptionDuringPreCondition = new Local(Identifier.For("SS$exceptionDuringPreCondition" + i),SystemTypes.Exception);
        Local exceptionDuringPreCondition3 = new Local(Identifier.For("SS$objectExceptionDuringPreCondition" + i),SystemTypes.Object);
        Expression cond = r.Condition;
        string condition = cond != null && cond.SourceContext.SourceText != null && cond.SourceContext.SourceText.Length > 0 ?
          cond.SourceContext.SourceText : "<unknown condition>";
        Expression ec2;
        Expression ec3;
        if (noAllocationAllowed) {
          ec2 = ec3 = new MemberBinding(null, SystemTypes.PreAllocatedExceptions.GetField(Identifier.For("InvalidContract")));
        }
        else {
          MemberBinding excBinding2 = new MemberBinding(null, SystemTypes.InvalidContractException.GetConstructor(SystemTypes.String, SystemTypes.Exception));
          MemberBinding excBinding3 = new MemberBinding(null, SystemTypes.InvalidContractException.GetConstructor(SystemTypes.String));
          string msg2 = "Exception occurred during evaluation of precondition '" + condition + "' in method '" + currentMethod.FullName + "'";
          ec2 = new Construct(excBinding2, new ExpressionList(new Literal(msg2, SystemTypes.String), exceptionDuringPreCondition));
          ec3 = new Construct(excBinding3, new ExpressionList(new Literal(msg2, SystemTypes.String)));
        }

        #region If the precondition fails, throw an exception
        Expression throwExpression = null;
        #region Create the expression to throw. Deal with different subtypes of Requires
        if (noAllocationAllowed) {
          throwExpression = new MemberBinding(null, SystemTypes.PreAllocatedExceptions.GetField(Identifier.For("Requires")));
        }
        else {
          if (r is RequiresPlain) {
            MemberBinding excBinding = new MemberBinding(null, SystemTypes.RequiresException.GetConstructor(SystemTypes.String));
            Construct ec = new Construct(excBinding, new ExpressionList());
            string msg = "Precondition '" + condition + "' violated from method '" + currentMethod.FullName + "'";
            ec.Operands.Add(new Literal(msg, SystemTypes.String));
            throwExpression = ec;
          }
          else if (r is RequiresOtherwise) {
            RequiresOtherwise otherwise = (RequiresOtherwise)r;
            if (otherwise.ThrowException is Literal) {
              // it was "requires P otherwise E" where E is a type name of an exception class
              Literal l = (Literal)otherwise.ThrowException;
              Class exceptionClass = (Class)l.Value;
              MemberBinding excBinding = new MemberBinding(null, this.GetTypeView(exceptionClass).GetConstructor());
              // what to do if there is no nullary constructor? I guess that should have been checked in the context checker
              Construct ec = new Construct(excBinding, new ExpressionList());
              throwExpression = ec;
            }
            else {
              // it was "requires P otherwise new E(...)" (or some other expression whose value is an exception)
              throwExpression = this.VisitExpression(otherwise.ThrowException);
            }
          }
          else {
            Debug.Assert(false, "Expecting only RequiresOtherwise and RequiresPlain as subtypes of Requires");
          }
        }
        #endregion
        Throw t = new Throw(throwExpression,r.SourceContext);
        #endregion

        Block pre_i_holds = new Block();

        //CatchList cl = new CatchList(2);
        //cl.Add(new Catch(new Block(new StatementList(new Throw(ec2,r.Condition.SourceContext))),exceptionDuringPreCondition,SystemTypes.Exception));
        //cl.Add(new Catch(new Block(new StatementList(new Throw(ec3,r.Condition.SourceContext))),exceptionDuringPreCondition3,SystemTypes.Object));

        //Try tryPre = new Try(new Block(new StatementList(new If(r.Condition,new Block(new StatementList(new Branch(null,pre_i_holds))),null))),cl,null,null,null);
        //preConditionBlock.Statements.Add(tryPre);
        preConditionBlock.Statements.Add(new If(r.Condition,new Block(new StatementList(new Branch(null,pre_i_holds))),null));
        preConditionBlock.Statements.Add(t);
        preConditionBlock.Statements.Add(pre_i_holds);

      }

      preConditionBlock = this.VisitBlock(preConditionBlock);
      this.currentContractPrelude.Statements.Add(preConditionBlock);
      return Requires;
    }
Пример #6
0
        private void ProcessClosureClass(Method method, TypeNode closure, bool isAsync)
        {
            Contract.Requires(method != null);
            Contract.Requires(closure != null);

            Method movenext = closure.GetMethod(StandardIds.MoveNext);

            if (movenext == null) return;

            movenext.IsAsync = isAsync;
            if (movenext.Body == null) return;

            if (movenext.Body.Statements == null) return;

            SourceContext defaultSourceContext;
            Block contractInitializerBlock = new Block(new StatementList());

            HelperMethods.StackDepthTracker dupStackTracker = new HelperMethods.StackDepthTracker();
            AssumeBlock originalContractPosition;

            StatementList contractClump = GetContractClumpFromMoveNext(method, movenext, contractNodes,
                contractInitializerBlock.Statements, out defaultSourceContext, ref dupStackTracker,
                out originalContractPosition);

            if (contractClump != null)
            {
                // Look for bad stuff

                BadStuff(method, contractClump, defaultSourceContext);

                // Make sure any locals in the contracts are disjoint from the locals in the rest of the body

                // can use the same one throughout
                GatherLocals gatherLocals = new GatherLocals();

                // Make sure that the entire contract section is closed.
                if (!CheckClump(movenext, gatherLocals, currentMethodSourceContext, new Block(contractClump)))
                {
                    movenext.ClearBody();
                    return;

                }
                // Checking that had the side effect of populating the hashtable, but now each contract will be individually visited.
                // That process needs to start with a fresh table.
                gatherLocals.Locals = new TrivialHashtable();
                RequiresList Preconditions = new RequiresList();
                EnsuresList Postconditions = new EnsuresList();
                RequiresList Validations = new RequiresList();
                EnsuresList modelPostconditions = new EnsuresList();
                EnsuresList asyncPostconditions = null;

                // REVIEW: What should we do with the Validations in this case? Should we map them to the enumerator method? Maybe not, since without
                // rewriting this won't happen.
                if (!ExtractFromClump(contractClump, movenext, gatherLocals, Preconditions, Postconditions, Validations,
                    modelPostconditions, defaultSourceContext, method, contractInitializerBlock, ref dupStackTracker))
                {
                    movenext.ClearBody();
                    return;
                }

                if (isAsync)
                {
                    asyncPostconditions = SplitAsyncEnsures(ref Postconditions, method);
                }

                try
                {
                    // Next is to attach the preconditions to method (instead of movenext)
                    // To do so, we have to duplicate the expressions and statements in Precondition, Postcondition and contractInitializerBlock
                    Duplicator dup = new Duplicator(closure.DeclaringModule, method.DeclaringType);

                    var origPreconditions = Preconditions;
                    var origValidations = Validations;
                    var origcontractInitializerBlock = contractInitializerBlock;

                    Preconditions = dup.VisitRequiresList(Preconditions);
                    Postconditions = dup.VisitEnsuresList(Postconditions);
                    Validations = dup.VisitRequiresList(Validations);
                    contractInitializerBlock = dup.VisitBlock(contractInitializerBlock);
                    asyncPostconditions = dup.VisitEnsuresList(asyncPostconditions);

                    var mapClosureExpToOriginal = BuildMappingFromClosureToOriginal(closure, movenext, method);

                    Preconditions = mapClosureExpToOriginal.Apply(Preconditions);
                    Postconditions = mapClosureExpToOriginal.Apply(Postconditions);
                    Validations = mapClosureExpToOriginal.Apply(Validations);
                    contractInitializerBlock = mapClosureExpToOriginal.Apply(contractInitializerBlock);
                    asyncPostconditions = mapClosureExpToOriginal.Apply(asyncPostconditions);

                    //MemberList members = FindClosureMembersInContract(closure, movenext);
                    // MakeClosureAccessibleToOriginalMethod(closure, members);
                    if (method.Contract == null)
                        method.Contract = new MethodContract(method);

                    method.Contract.Requires = Preconditions;
                    method.Contract.Validations = Validations;

                    // Postconditions are sanity checked here, because Result<T> must be compared against the
                    // return type of the original method. It is most conveniently done after the type substitution. 
                    // TODO: refactor the checking part altogether out of ExtractFromClump. 
                    method.Contract.Ensures = Postconditions;
                    method.Contract.ModelEnsures = modelPostconditions;
                    method.Contract.ContractInitializer = contractInitializerBlock;
                    method.Contract.AsyncEnsures = asyncPostconditions;

                    // Following replacement causes some weird issues for complex preconditions (like x != null && x.Length > 0)
                    // when CCRewriter is used with /publicsurface or Preconditions only.
                    // This fix could be temporal and proper fix would be applied in the future.
                    // After discussion this issue with original CC authors (Mike Barnett and Francesco Logozzo),
                    // we decided that this fix is safe and lack of Assume statement in the MoveNext method will not affect
                    // customers (neither CCRewriter customers nor CCCheck customers).
                    // If this assumption would not be true in the future, proper fix should be applied.
                    // put requires as assumes into movenext method at original position
                    // ReplaceRequiresWithAssumeInMoveNext(origPreconditions, originalContractPosition);

                    // no postPreamble to initialize, as method is not a ctor
                }
                finally
                {
                    // this is done in caller!!!

                    //// normalize contract by forcing IsPure to look at attributes and removing contract it is empty
                    //var contract = method.Contract;
                    //var isPure = contract.IsPure;

                    //if (!isPure && contract.RequiresCount == 0 && contract.EnsuresCount == 0 && contract.ModelEnsuresCount == 0 && contract.ValidationsCount == 0 && contract.AsyncEnsuresCount == 0)
                    //{
                    //  method.Contract = null;
                    //} else
                    //{
                    //  // turn helper method calls to Result, OldValue, ValueAtReturn into proper AST nodes.
                    //  this.extractionFinalizer.VisitMethodContract(method.Contract);
                    //}
                }
            }
        }
Пример #7
0
 public virtual RequiresList VisitRequiresList(RequiresList Requires) {
   if (Requires == null) return null;
   for (int i = 0, n = Requires.Count; i < n; i++)
     Requires[i] = (Requires) this.Visit(Requires[i]);
   return Requires;
 }
Пример #8
0
        private void CopyValidatorContracts(Method targetMethod, Method validatorMethodInstance, Expression targetObject,
            ExpressionList actuals, RequiresList Preconditions, SourceContext useSite, Block validatorPrefix)
        {
            // make sure to have extracted contracts from the validator method prior
            if (validatorMethodInstance.DeclaringType.DeclaringModule == targetMethod.DeclaringType.DeclaringModule)
            {
                var validatorMethod = validatorMethodInstance;

                while (validatorMethod.Template != null)
                {
                    validatorMethod = validatorMethod.Template;
                }

                this.VisitMethod(validatorMethod);
            }

            if (validatorMethodInstance.Contract == null) return;

            var copier = new AbbreviationDuplicator(validatorMethodInstance, targetMethod, this.contractNodes,
                validatorMethodInstance, targetObject, actuals);

            var validatorContract = HelperMethods.DuplicateContractAndClosureParts(copier, targetMethod,
                validatorMethodInstance, this.contractNodes, false);

            if (validatorContract == null) return;

            MoveValidatorRequires(targetMethod, validatorContract.Requires, Preconditions, useSite,
                validatorContract.ContractInitializer, validatorPrefix);
        }
Пример #9
0
 private void EmitInterleavedValidationsAndRequires(Method method, List<Requires> inherited, RequiresList validations, Block newBody)
 {
   List<Requires> reqSequence = new List<Requires>();
   if (validations != null)
   {
     foreach (var val in validations)
     {
       var ro = val as RequiresOtherwise;
       if (ro != null)
       {
         FlushEmitOrdinaryRequires(reqSequence, method, newBody);
         if (this.Emit(RuntimeContractEmitFlags.LegacyRequires))
         {
           newBody.Statements.Add(GenerateValidationCode(ro));
         }
       }
       else
       {
         if (EmitRequires((RequiresPlain)val, this.skipQuantifiers))
         {
           reqSequence.Add(val);
         }
       }
     }
   }
   if (inherited.Count > 0)
   {
     foreach (var req in inherited) { reqSequence.Add(req); }
   }
   FlushEmitOrdinaryRequires(reqSequence, method, newBody);
 }
Пример #10
0
 /// <summary>
 /// Need to have this override so that inherited preconditions are not
 /// checked again. 
 /// </summary>
 /// <param name="Requires"></param>
 /// <returns></returns>
 public override RequiresList VisitRequiresList(RequiresList Requires) {
   if (Requires == null) return null;
   for (int i = 0, n = Requires.Count; i < n; i++) {
     if (Requires[i] == null || Requires[i].Inherited) {
       continue;
     }
     Requires[i] = (Requires)this.Visit(Requires[i]);
   }
   return Requires;
 }
Пример #11
0
 public virtual void VisitRequiresList(RequiresList Requires)
 {
   if (Requires == null) return;
   for (int i = 0, n = Requires.Count; i < n; i++)
     this.Visit(Requires[i]);
 }
Пример #12
0
 public override RequiresList VisitRequiresList(RequiresList Requires)
 {
   if (Requires == null) return null;
   return base.VisitRequiresList(Requires.Clone());
 }
Пример #13
0
 public virtual RequiresList VisitRequiresList(RequiresList requires1, RequiresList requires2) {
   if (requires1 == null) return null;
   for (int i = 0, n = requires1.Count, m = requires2 == null ? 0 : requires2.Count; i < n; i++) {
     //^ assert requires2 != null;
     if (i >= m)
       requires1[i] = (Requires)this.Visit(requires1[i], null);
     else
       requires1[i] = (Requires)this.Visit(requires1[i], requires2[i]);
   }
   return requires1;
 }
Пример #14
0
        private Invariant TryLiftingPropertyInvariantToPropertyRequiresEnsures(TypeNode typeNode, Invariant invariant)
        {
            List<Member> referencedMembers;
            var autoprops = AutoPropFinder.FindAutoProperty(this, typeNode, invariant.Condition, out referencedMembers);

            if (autoprops == null || autoprops.Count == 0) return invariant;

            foreach (var autoPropertyUsed in autoprops)
            {
                var getter = HelperMethods.Unspecialize(autoPropertyUsed.Getter);
                if (!AllReferencedMembersAsVisibleAs(getter, referencedMembers)) continue;

                var setter = HelperMethods.Unspecialize(autoPropertyUsed.Setter);

                if (getter.Contract == null)
                {
                    getter.Contract = new MethodContract(getter);
                }

                if (setter.Contract == null)
                {
                    setter.Contract = new MethodContract(setter);
                }

                var ensuresList = getter.Contract.Ensures;
                if (ensuresList == null)
                {
                    getter.Contract.Ensures = ensuresList = new EnsuresList();
                }

                var requiresList = setter.Contract.Requires;
                if (requiresList == null)
                {
                    setter.Contract.Requires = requiresList = new RequiresList();
                }

                var validationList = setter.Contract.Validations;
                if (validationList == null)
                {
                    setter.Contract.Validations = validationList = new RequiresList();
                }

                Requires req;
                Ensures ens;
                ChangePropertyInvariantIntoRequiresEnsures.Transform(this, autoPropertyUsed, invariant, out req, out ens);

                requiresList.Add(req);
                validationList.Add(req);
                ensuresList.Add(ens);

                // make sure the property getter isn't visited again
                if (!this.visitedMethods.ContainsKey(autoPropertyUsed.Getter))
                {
                    this.visitedMethods.Add(autoPropertyUsed.Getter, autoPropertyUsed.Getter);
                }

                if (!this.visitedMethods.ContainsKey(autoPropertyUsed.Setter))
                {
                    this.visitedMethods.Add(autoPropertyUsed.Setter, autoPropertyUsed.Setter);
                }
            }

            ReplaceAutoPropertiesWithCorrespondingFields.Replace(autoprops, invariant);
            return invariant;
        }
Пример #15
0
        /// <summary>
        /// </summary>
        /// <param name="validationContractInitializer">possibly empty initializer from closures in validators. Must be added as prefix to first requires</param>
        /// <param name="validationPrefix">Possibly empty statement list of code preceeding validator call. Must be added to first
        /// requires.</param>
        private void MoveValidatorRequires(Method targetMethod, RequiresList requiresList, RequiresList Preconditions,
            SourceContext useSite, Block validationContractInitializer, Block validationPrefix)
        {
            bool isFromValidation = true;

            if (requiresList == null) return;

            foreach (RequiresPlain req in requiresList)
            {
                if (!req.DefSite.IsValid)
                {
                    req.DefSite = req.SourceContext;
                }

                req.SourceContext = useSite;
                req.IsFromValidation = isFromValidation; // mark that we copied this from a validator when necessary

                // re-sanitize user message for this context
                req.UserMessage = SanitizeUserMessage(targetMethod, req.UserMessage, useSite);

                // check if first requires and add prefixes
                if (HelperMethods.IsNonTrivial(validationPrefix))
                {
                    req.Condition =
                        new BlockExpression(
                            new Block(new StatementList(validationPrefix, new ExpressionStatement(req.Condition))));
                    validationPrefix = null;
                }
                
                if (HelperMethods.IsNonTrivial(validationContractInitializer))
                {
                    req.Condition =
                        new BlockExpression(
                            new Block(new StatementList(validationContractInitializer,
                                new ExpressionStatement(req.Condition))));
                    validationContractInitializer = null;
                }

                Preconditions.Add(req);
            }
        }
Пример #16
0
        private bool ExtractFromClump(StatementList contractClump, Method method, GatherLocals gatherLocals,
            RequiresList Preconditions, EnsuresList Postconditions, RequiresList validations,
            EnsuresList modelPostconditions, SourceContext defaultContext, Method originalMethod,
            Block contractInitializer, ref HelperMethods.StackDepthTracker dupStackTracker)
        {
            // set the state so that the contract clump is used for extraction (as opposed to the method body as it used to)
            StatementList stmts = contractClump;

            int beginning = 0;
            int n = stmts.Count;
            int seginning = HelperMethods.FindNextRealStatement(((Block) stmts[beginning]).Statements, 0);

            bool endContractFound = false;
            bool postConditionFound = false;

            SourceContext currentSourceContext;

            for (int i = beginning; i < n; i++)
            {
                Block b = (Block) stmts[i];
                if (b == null) continue;

                for (int j = 0, m = b.Statements == null ? 0 : b.Statements.Count; j < m; j++)
                {
                    if (dupStackTracker.IsValid && dupStackTracker.Depth >= 0)
                    {
                        b.Statements[j] = dupStackTracker.Visit(b.Statements[j]);
                    }

                    Statement s = b.Statements[j];
                    if (s == null) continue;

                    Block currentClump;
                    Throw t = null;
                    t = s as Throw;

                    Method calledMethod = HelperMethods.IsMethodCall(s);
                    if ((t != null ||
                         (calledMethod != null &&
                          calledMethod.DeclaringType != null &&
                          calledMethod.DeclaringType != this.contractNodes.ContractClass &&
                          HelperMethods.IsVoidType(calledMethod.ReturnType) &&
                          !this.contractNodes.IsContractOrValidatorOrAbbreviatorMethod(calledMethod))))
                    {
                        // Treat throw statements as (part of) a precondition

                        // don't accept "throw ..." unless it comes in the "precondition section"
                        // then treat the current clump as a precondition, but need to massage it a bit:
                        // all branches to the block just after the throw should be modified to be branches to
                        // a new manufactured block that sets a fresh local to "true". The
                        // throw itself should be changed to set the same local to "false". That way the
                        // clump can be treated as the value of precondition (because the branch polarity has
                        // already been negated as part of the code gen).

                        // This test was supposed to be a sanity check that the current block contained
                        // only "throw ..." or else "nop; throw ...". But I've also seen "ThrowHelper.Throw(...); nop",
                        // so I'm just going to comment this out for now.
                        //if (!((m == 1 && j == 0) || (m == 2 && j == 1))) {
                        //  Preconditions = new RequiresList();
                        //  Postconditions = new EnsuresList();
                        //  return; // throw new ExtractorException();
                        //}

                        Expression exception;

                        // The clump being extracted may contain code/blocks that represent (part of)
                        // the expression that is being thrown (if the original throw expression had
                        // control flow in it from boolean expressions and/or ternary expressions).

                        b.Statements[j] = null; // wipe out throw statement

                        currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j));
                        int currentClumpLength = i - beginning + 1;

                        // there better be a next block because that must have been the target for all of the branches
                        // that didn't cause the throw to happen
                        if (!(i < n - 1))
                        {
                            this.HandleError(method, 1027, "Malformed contract.", s.SourceContext);
                            return false;
                        }

                        Block nextBlock = (Block) stmts[i + 1]; // cast succeeds because body is clump
                        Local valueOfPrecondition = new Local(Identifier.For("_preConditionHolds"), SystemTypes.Boolean);
                        Block preconditionHolds = new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.True)));

                        ReplaceBranchTarget rbt = new ReplaceBranchTarget(nextBlock, preconditionHolds);
                        rbt.VisitBlock(currentClump);

                        int ILOffset;
                        CountPopExpressions cpe = new CountPopExpressions();
                        currentSourceContext = s.SourceContext;
                        cpe.Visit(s);

                        if (0 < cpe.PopOccurrences)
                        {
                            // then there is a set of blocks that represent the exception: the Reader
                            // was not able to decompile it back into an expression. Extract the set
                            // from the current clump and make it into a block expression

                            // Find the last block that has a branch to "preconditionHolds". After that are all of the blocks
                            // that represent the evaluation of the exception
                            int branchBlockIndex = currentClumpLength - 2;

                            // can't be the current block: that has the throw in it
                            while (0 <= branchBlockIndex)
                            {
                                Block possibleBranchBlock = currentClump.Statements[branchBlockIndex] as Block;
                                Branch br = possibleBranchBlock.Statements[possibleBranchBlock.Statements.Count - 1] as Branch;
                                if (br != null && br.Target == preconditionHolds)
                                {
                                    break;
                                }

                                branchBlockIndex--;
                            }

                            if (branchBlockIndex < 0)
                            {
                                this.HandleError(method, 1028, "Malformed exception constructor in contract.", defaultContext);
                                return false;
                            }

                            Block exceptionBlock =
                                new Block(HelperMethods.ExtractClump(currentClump.Statements, branchBlockIndex + 1, 0,
                                    currentClumpLength - 1,
                                    ((Block) currentClump.Statements[currentClumpLength - 1]).Statements.Count - 1));

                            exceptionBlock.Statements.Add(new ExpressionStatement(t.Expression));
                            SourceContext sctx = ((Block) exceptionBlock.Statements[0]).Statements[0].SourceContext;

                            if (sctx.IsValid)
                            {
                                currentSourceContext = sctx;
                            }
                            else
                            {
                                SourceContext tmp;
                                bool foundContext = HelperMethods.GetLastSourceContext(exceptionBlock.Statements, out tmp);
                                if (foundContext)
                                    currentSourceContext = tmp;
                            }

                            if (!CheckClump(method, gatherLocals, currentSourceContext, exceptionBlock)) return false;
                            
                            exception = new BlockExpression(exceptionBlock, SystemTypes.Exception);
                            ILOffset = t.ILOffset;
                        }
                        else
                        {
                            currentSourceContext = s.SourceContext;
                            if (t != null)
                            {
                                // then the statement is "throw ..."
                                exception = t.Expression;
                                ILOffset = t.ILOffset;
                            }
                            else
                            {
                                ExpressionStatement throwHelperCall = s as ExpressionStatement;

                                Debug.Assert(throwHelperCall != null);

                                exception = throwHelperCall.Expression;
                                ILOffset = s.ILOffset;
                            }

                            exception.SourceContext = currentSourceContext;
                            SourceContext tmp;

                            bool foundContext = HelperMethods.GetLastSourceContext(currentClump.Statements, out tmp);
                            if (foundContext)
                                currentSourceContext = tmp;
                        }

                        Block returnValueOfPrecondition = new Block(new StatementList(new ExpressionStatement(valueOfPrecondition)));
                        Statement extraAssumeFalse = this.ExtraAssumeFalseOnThrow();

                        Block preconditionFails =
                            new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.False),
                                extraAssumeFalse, new Branch(null, returnValueOfPrecondition, true, false, false)));

                        //Block preconditionFails = new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.False), new Branch(null, returnValueOfPrecondition, true, false, false)));
                        currentClump.Statements.Add(preconditionFails); // replace throw statement
                        currentClump.Statements.Add(preconditionHolds);
                        currentClump.Statements.Add(returnValueOfPrecondition);

                        if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump)) return false;

                        BlockExpression be = new BlockExpression(currentClump, SystemTypes.Boolean);
                        be.SourceContext = currentSourceContext;

                        var ro = new RequiresOtherwise(be, exception);
                        ro.ILOffset = ILOffset;
                        ro.SourceContext = currentSourceContext;

                        if (postConditionFound)
                        {
                            HandleError(originalMethod, 1013, "Precondition found after postcondition.", currentSourceContext);
                            return false;
                        }

                        validations.Add(ro);

                        var req = new RequiresPlain(be, FindExceptionThrown.Find(exception));
                        req.IsFromValidation = true;
                        req.ILOffset = ro.ILOffset;
                        req.SourceContext = ro.SourceContext;

                        Preconditions.Add(req);
                    }
                    else
                    {
                        if (contractNodes.IsContractMethod(calledMethod))
                        {
                            // Treat calls to contract methods

                            if (endContractFound)
                            {
                                HandleError(originalMethod, 1012, "Contract call found after prior EndContractBlock.", s.SourceContext);
                                break;
                            }

                            if (contractNodes.IsEndContract(calledMethod))
                            {
                                endContractFound = true;
                                continue;
                            }

                            MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall;
                            Expression arg = mc.Operands[0];
                            arg.SourceContext = s.SourceContext;
                            MethodContractElement mce;
                            currentSourceContext = s.SourceContext;
                            Expression condition;

                            if (beginning == i && seginning == j)
                            {
                                // Deal with the simple case: the reader decompiled the call into a single statement
                                condition = arg;
                            }
                            else
                            {
                                b.Statements[j] = new ExpressionStatement(arg);

                                // construct a clump from
                                // methodBody.Statements[beginning].Statements[seginning] to
                                // methodBody.Statements[i].Statements[j]
                                currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j));
                                if (!currentSourceContext.IsValid)
                                {
                                    // then a good source context has not been found yet. Grovel around in the clump
                                    // to see if there is a better one
                                    SourceContext sctx;
                                    if (HelperMethods.FindContext(currentClump, currentSourceContext, out sctx))
                                        currentSourceContext = sctx;
                                }

                                if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump))
                                    return false;

                                BlockExpression be = new BlockExpression(currentClump);
                                condition = be;
                            }

                            condition.SourceContext = currentSourceContext;
                            if (contractNodes.IsPlainPrecondition(calledMethod))
                            {
                                var req = new RequiresPlain(condition);
                                contractNodes.IsRequiresWithException(calledMethod, out req.ExceptionType);

                                mce = req;
                            }
                            else if (this.contractNodes.IsPostcondition(calledMethod))
                            {
                                mce = new EnsuresNormal(condition);
                            }
                            else if (contractNodes.IsExceptionalPostcondition(calledMethod))
                            {
                                EnsuresExceptional ee = new EnsuresExceptional(condition);
                                // Extract the type of exception.
                                ee.Type = calledMethod.TemplateArguments[0];
                                mce = ee;
                            }
                            else
                            {
                                throw new InvalidOperationException("Cannot recognize contract method");
                            }

                            mce.SourceContext = currentSourceContext;
                            mce.ILOffset = mc.ILOffset;
                            if (1 < mc.Operands.Count)
                            {
                                var candidate = SanitizeUserMessage(method, mc.Operands[1], currentSourceContext);
                                mce.UserMessage = candidate;
                            }
                            if (2 < mc.Operands.Count)
                            {
                                Literal lit = mc.Operands[2] as Literal;
                                if (lit != null)
                                {
                                    mce.SourceConditionText = lit;
                                }
                            }

                            // determine Model status

                            mce.UsesModels = CodeInspector.UsesModel(mce.Assertion, this.contractNodes);

                            // Check context rules

                            switch (mce.NodeType)
                            {
                                case NodeType.RequiresPlain:
                                    if (postConditionFound)
                                    {
                                        this.HandleError(originalMethod, 1014, "Precondition found after postcondition.", currentSourceContext);
                                        return false;
                                    }
                                    if (mce.UsesModels)
                                    {
                                        this.HandleError(originalMethod, 1073, "Preconditions may not refer to model members.", currentSourceContext);
                                        return false;
                                    }

                                    var rp = (RequiresPlain) mce;

                                    Preconditions.Add(rp);
                                    validations.Add(rp); // also add to the internal validation list
                                    break;

                                // TODO: check visibility of post conditions based on visibility of possible implementation
                                case NodeType.EnsuresNormal:
                                case NodeType.EnsuresExceptional:
                                    Ensures ensures = (Ensures) mce;
                                    if (mce.UsesModels)
                                    {
                                        if (this.IncludeModels)
                                        {
                                            modelPostconditions.Add(ensures);
                                        }
                                    }
                                    else
                                    {
                                        Postconditions.Add(ensures);
                                    }
                                    postConditionFound = true;
                                    break;
                            }
                        }
                        else if (ContractNodes.IsValidatorMethod(calledMethod))
                        {
                            // Treat calls to Contract validators

                            if (endContractFound)
                            {
                                this.HandleError(originalMethod, 1012,
                                    "Contract call found after prior EndContractBlock.", s.SourceContext);
                                break;
                            }

                            MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall;
                            var memberBinding = (MemberBinding) mc.Callee;

                            currentSourceContext = s.SourceContext;
                            Statement validation;
                            Block validationPrefix;
                            if (beginning == i && seginning == j)
                            {
                                // Deal with the simple case: the reader decompiled the call into a single statement
                                validation = s;
                                validationPrefix = null;
                            }
                            else
                            {
                                // The clump may contain multiple statements ending in the validator call.
                                //   to extract the code as Requires<E>, we need to keep the statements preceeding
                                //   the validator call, as they may contain local initialization etc. These should go
                                //   into the first Requires<E> that the validator expands to. This way, if there are
                                //   no Requires<E> expanded from the validator, then the statements can be omitted.
                                //   At the same time, the statements won't be duplicated when validations are emitted.
                                //
                                //   If the validator call contains any pops, then the extraction must fail saying it
                                //   is too complicated.

                                // must null out statement with call before extract clump
                                b.Statements[j] = null; // we have a copy in mc, s
                                validationPrefix = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j));

                                if (!currentSourceContext.IsValid)
                                {
                                    // then a good source context has not been found yet. Grovel around in the clump
                                    // to see if there is a better one
                                    SourceContext sctx;
                                    if (HelperMethods.FindContext(validationPrefix, currentSourceContext, out sctx))
                                        currentSourceContext = sctx;
                                }

                                if (CountPopExpressions.Count(mc) > 0)
                                {
                                    this.HandleError(method, 1071,
                                        "Arguments to contract validator call are too complicated. Please simplify.",
                                        currentSourceContext);
                                    return false;
                                }

                                if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, validationPrefix))
                                    return false;

                                validation = new Block(new StatementList(validationPrefix, s));
                                validation.SourceContext = currentSourceContext;
                            }
                            var ro = new RequiresOtherwise(null, new BlockExpression(new Block(new StatementList(validation))));

                            validations.Add(ro);
                            CopyValidatorContracts(
                                method, calledMethod, memberBinding.TargetObject, mc.Operands,
                                Preconditions, currentSourceContext, validationPrefix);
                        }
                        else if (ContractNodes.IsAbbreviatorMethod(calledMethod))
                        {
                            // Treat calls to Contract abbreviators

                            if (endContractFound)
                            {
                                this.HandleError(originalMethod, 1012, "Contract call found after prior EndContractBlock.", s.SourceContext);
                                break;
                            }

                            MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall;
                            var memberBinding = (MemberBinding) mc.Callee;
                            currentSourceContext = s.SourceContext;
                            if (beginning == i && seginning == j)
                            {
                                // Deal with the simple case: the reader decompiled the call into a single statement

                                // nothing to do. All is in the call and its arguments
                            }
                            else
                            {
                                // The clump may contain multiple statements ending in the abbreviator call.
                                // We need to keep the statements preceeding the abbreviator call and add them to the 
                                // contract initializer block. The reason we cannot add them to the first expansion contract
                                // of the abbreviator is that the abbreviator may give rise to closure initialization which will
                                // be hoisted into the closure initializer block. This closure initializer may refer to the
                                // locals initialized by the present statement sequence, so it must precede it. 
                                //
                                //   If the abbreviator call contains any pops, then the extraction must fail saying it
                                //   is too complicated.
                                // grab prefix of clump minus last call statement.

                                // must null out current call statement before we extract clump (ow. it stays in body)
                                b.Statements[j] = null;
                                currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j));

                                if (!currentSourceContext.IsValid)
                                {
                                    // then a good source context has not been found yet. Grovel around in the clump
                                    // to see if there is a better one
                                    SourceContext sctx;
                                    if (HelperMethods.FindContext(currentClump, currentSourceContext, out sctx))
                                        currentSourceContext = sctx;
                                }

                                if (CountPopExpressions.Count(mc) > 0)
                                {
                                    this.HandleError(method, 1070,
                                        "Arguments to contract abbreviator call are too complicated. Please simplify.",
                                        currentSourceContext);
                                    return false;
                                }

                                if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump))
                                    return false;

                                if (HelperMethods.IsNonTrivial(currentClump))
                                {
                                    contractInitializer.Statements.Add(currentClump);
                                }
                            }

                            CopyAbbreviatorContracts(method, calledMethod, memberBinding.TargetObject, mc.Operands,
                                Preconditions, Postconditions, currentSourceContext, validations, contractInitializer);
                        }
                        else
                        {
                            // important to continue here and accumulate blocks/statements for next contract!
                            if (i == beginning && j == seginning && s.NodeType == NodeType.Nop)
                            {
                                // nop following contract is often associated with previous code, so skip it
                                seginning = j + 1;
                            }

                            continue;
                        }
                    }

                    // Re-initialize current state after contract has been found

                    beginning = i;
                    seginning = j + 1;

                    //seginning = HelperMethods.FindNextRealStatement(((Block)stmts[i]).Statements, j + 1);
                    if (seginning < 0) seginning = 0;
                    
                    //b = (Block)stmts[i]; // IMPORTANT! Need this to keep "b" in sync
                }
            }

            if (this.verbose)
            {
                Console.WriteLine("\tNumber of Preconditions: " + Preconditions.Count);
                Console.WriteLine("\tNumber of Postconditions: " + Postconditions.Count);
            }

            return true;
        }
Пример #17
0
        private void MoveAbbreviatorRequires(Method targetMethod, RequiresList requiresList, RequiresList Preconditions,
            RequiresList validations, SourceContext useSite)
        {
            Contract.Requires(validations != null);

            if (requiresList == null) return;

            foreach (RequiresPlain req in requiresList)
            {
                if (!req.DefSite.IsValid)
                {
                    req.DefSite = req.SourceContext;
                }

                req.SourceContext = useSite;
                req.IsFromValidation = false;

                // re-sanitize user message for this context
                req.UserMessage = SanitizeUserMessage(targetMethod, req.UserMessage, useSite);

                Preconditions.Add(req);
                validations.Add(req); // we keep everything on both lists so we can emit for validation or standard
            }
        }
Пример #18
0
        private void CopyAbbreviatorContracts(Method targetMethod, Method abbreviatorMethodInstance,
            Expression targetObject, ExpressionList actuals, RequiresList Preconditions, EnsuresList Postconditions,
            SourceContext useSite, RequiresList validations, Block contractInitializer)
        {
            Contract.Requires(validations != null);

            // make sure to have extracted contracts from the abbreviator method prior
            if (abbreviatorMethodInstance.DeclaringType.DeclaringModule == targetMethod.DeclaringType.DeclaringModule)
            {
                var abbrevMethod = abbreviatorMethodInstance;

                while (abbrevMethod.Template != null)
                {
                    abbrevMethod = abbrevMethod.Template;
                }

                this.VisitMethod(abbrevMethod);
            }

            if (abbreviatorMethodInstance.Contract == null) return;

            var copier = new AbbreviationDuplicator(abbreviatorMethodInstance, targetMethod, this.contractNodes,
                abbreviatorMethodInstance, targetObject, actuals);

            var abbrevContract = HelperMethods.DuplicateContractAndClosureParts(copier, targetMethod,
                abbreviatorMethodInstance, this.contractNodes, true);

            if (abbrevContract == null) return;

            if (HelperMethods.IsNonTrivial(abbrevContract.ContractInitializer))
            {
                contractInitializer.Statements.Add(abbrevContract.ContractInitializer);
            }

            MoveAbbreviatorRequires(targetMethod, abbrevContract.Requires, Preconditions, validations, useSite);
            MoveAbbreviatorEnsures(targetMethod, abbrevContract.Ensures, Postconditions, useSite);
        }
Пример #19
0
 public EventingVisitor(Action<RequiresList> visitRequiresList) { VisitedRequiresList += visitRequiresList; } public event Action<RequiresList> VisitedRequiresList; public override RequiresList VisitRequiresList(RequiresList Requires) { if (VisitedRequiresList != null) VisitedRequiresList(Requires); return base.VisitRequiresList(Requires); }