public override void VisitEnsuresExceptional(EnsuresExceptional exceptional)
        {
            // Since we can copy contracts around now, we may already have the source text if it comes from a contract reference assembly
            if (exceptional.SourceConditionText != null)
            {
                return;
            }
            string source = GetSource("Contract.Ensures", ContextForTextExtraction(exceptional));

            if (source == null)
            {
                if (writeOutput)
                {
                    Console.WriteLine("<error generating documentation>");
                }
            }
            else
            {
                exceptional.SourceConditionText = new Literal(source, SystemTypes.String);
                if (writeOutput)
                {
                    Indent();
                    Console.WriteLine("{0}", source);
                }
            }
        }
        public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional)
        {
            var result = base.VisitEnsuresExceptional(exceptional);

            result.UserMessage = (Expression)Visit(result.UserMessage);

            return(result);
        }
        public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional)
        {
            if (exceptional == null)
            {
                return(null);
            }

            var result = base.VisitEnsuresExceptional(exceptional);

            result.UserMessage = ExtractorVisitor.FilterUserMessage(this.targetMethod, result.UserMessage);

            return(result);
        }
Exemple #4
0
    public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional) {
      // BUGBUG? How safe is it to assume that the Variable is a NameBinding at this point?
      // But if it isn't what can possibly be done with it? If it isn't resolved to something,
      // the Checker pass will wipe it out.

      NameBinding nb = exceptional.Variable as NameBinding;
      if (nb != null) {
        exceptional.Variable = new Local(nb.Identifier, exceptional.Type);
      }
      exceptional.PostCondition = this.VisitBooleanExpression(exceptional.PostCondition);
      return exceptional;
    }
Exemple #5
0
 public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional){
   if (exceptional == null) return null;
   this.VisitResolvedTypeReference(exceptional.Type, exceptional.TypeExpression);
   return base.VisitEnsuresExceptional(exceptional);
 }
Exemple #6
0
 public virtual void VisitEnsuresExceptional(EnsuresExceptional exceptional)
 {
   if (exceptional == null) return;
   this.VisitExpression(exceptional.PostCondition);
   this.VisitTypeReference(exceptional.Type);
   this.VisitExpression(exceptional.Variable);
 }
            private void CheckEnsuresExceptional(Method method, EnsuresExceptional ensuresExceptional)
            {
                // F: Is this a precondition? Or simply return when method == null
                Contract.Requires(method != null);

                if (ensuresExceptional == null) return;
                if (ensuresExceptional.Type != null)
                {
                    if (!HelperMethods.IsTypeAsVisibleAs(ensuresExceptional.Type, method))
                    {
                        var msg =
                            string.Format(
                                "Exception type {0} in EnsuresOnThrow<E> has less visibility than enclosing method {1}",
                                ensuresExceptional.Type.FullName, method.FullName);

                        this.errorHandler(new Error(1037, msg, ensuresExceptional.SourceContext));
                    }
                }
            }
        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;
        }
Exemple #9
0
    private void ParseMethodContract(Method m, TokenSet followers, ref bool swallowedSemicolonAlready){
      bool savedParsingStatement = this.parsingStatement;
      if (this.currentToken != Token.EndOfFile) this.parsingStatement = true;
      if (!swallowedSemicolonAlready) m.SourceContext.EndPos = this.scanner.endPos;
      MethodContract mc = new MethodContract(m);
      SourceContext initialSourceContext = this.scanner.CurrentSourceContext;
      while ( Parser.ContractStart[this.currentToken] ) {
        SourceContext ctx = this.scanner.CurrentSourceContext;
        Node n = null;
        int finalPos = 0;
        switch ( this.currentToken ) {
          case Token.Requires: {
            this.GetNextToken();
            if (this.currentToken == Token.LeftBrace){
              this.HandleError(Error.ExpectedExpression);
              break; // without this, the left bracket gets parsed as an anonymous nested function
            }
            Expression e = this.ParseExpression(followers|ContractStart|Token.Otherwise);
            if (mc.Requires == null) mc.Requires = new RequiresList();
            if (this.currentToken != Token.Otherwise) {
              Requires r = new RequiresPlain(e);
              n = r;
              mc.Requires.Add(r);
            }else {
              this.Skip(Token.Otherwise);
              Expression e2 = this.ParseExpression(followers|ContractStart);
              Requires r = new RequiresOtherwise(e,e2);
              n = r;
              mc.Requires.Add(r);
            }
            finalPos = this.scanner.CurrentSourceContext.EndPos;
            swallowedSemicolonAlready= (this.currentToken == Token.Semicolon);
            this.SkipSemiColon(followers|ContractStart);
            break;
          }
          case Token.Modifies: {
            // modifies expressions have their source context set here within this
            // case, so don't use the variable "n" to hold on to the AST otherwise
            // it will have the wrong source context set for it at the end of the switch
            // statement
            n = null;
            this.insideModifiesClause = true;
            list : {
              this.GetNextToken(); // Token.Modifies or Token.Comma
              SourceContext sctx = this.scanner.CurrentSourceContext;
              Expression e = this.ParseExpression(followers | ContractStart | Token.Comma);
              if (mc.Modifies == null) mc.Modifies = new ExpressionList();
              if (e != null) { // REVIEW: does this just silently miss errors?
                sctx.EndPos = e.SourceContext.EndPos;
                ModifiesClause modClause = e as ModifiesClause;
                if (modClause != null) {
                  e.SourceContext = sctx;
                }
                else {
                  e = new UnaryExpression(e, NodeType.RefAddress, sctx);
                }
                mc.Modifies.Add(e);
              }
              if (this.currentToken == Token.Comma)
                goto list;
            }
            swallowedSemicolonAlready= (this.currentToken == Token.Semicolon);
            finalPos = this.scanner.CurrentSourceContext.EndPos;
            this.SkipSemiColon(followers|ContractStart);
            this.insideModifiesClause = false;
            break;
          }
          case Token.Ensures: {
            InEnsuresContext = true;
            this.GetNextToken();
            if (this.currentToken == Token.LeftBrace){
              this.HandleError(Error.ExpectedExpression);
              break; // without this, the left bracket gets parsed as an anonymous nested function
            }
            Expression e = this.ParseExpression(followers|ContractStart);
            if (mc.Ensures == null) mc.Ensures = new EnsuresList();
            EnsuresNormal en = new EnsuresNormal(e);
            n = en;
            mc.Ensures.Add(en);
            finalPos = this.scanner.CurrentSourceContext.EndPos;
            swallowedSemicolonAlready= (this.currentToken == Token.Semicolon);
            this.SkipSemiColon(followers|ContractStart);
            InEnsuresContext = false;
            break;
          }
          case Token.Throws: {
            this.GetNextToken();
            // throws (E1) ensures P;
            // throws (E1 e) ensures P;
            // throws E1 ensures P;
            // throws E1, E2, ...;
            // Note, for constuctors, only the last of these forms is allowed.
            if (mc.Ensures == null) {
              mc.Ensures = new EnsuresList();
              // Note, this list may be left empty in case of parsing errors below.
            }
            EnsuresExceptional exc = new EnsuresExceptional();
            exc.SourceContext = this.scanner.CurrentSourceContext;

            bool hasLeftParen = false;
            if (this.currentToken == Token.LeftParenthesis) {
              hasLeftParen = true;
              this.Skip(Token.LeftParenthesis);
            }
            exc.Type = exc.TypeExpression = this.ParseTypeExpression(Identifier.Empty, followers|Token.Identifier|Token.RightParenthesis|ContractStart);
            if (hasLeftParen && Parser.IdentifierOrNonReservedKeyword[this.currentToken]) {
              exc.Variable = this.scanner.GetIdentifier();
              exc.Variable.Type = exc.Type;
              this.GetNextToken();
            }else{
              exc.Variable = null; // need to be able to distinguish whether the source contains a variable or not
            }
            if (hasLeftParen) {
              this.Skip(Token.RightParenthesis);
            }

            if (hasLeftParen || this.currentToken == Token.Ensures) {
              // throws (E1) ensures P;
              // throws (E1 e) ensures P;
              // throws E1 ensures P;
              SourceContext ctxEnsures = this.scanner.CurrentSourceContext;
              this.Skip(Token.Ensures);
              InEnsuresContext = true;
              Expression ens = this.ParseExpression(followers|ContractStart);
              InEnsuresContext = false;
              // Do the constructor check now.  This is rather late, since the whole throws...ensures
              // has now been parsed, but this may lead to better parse-error recovery.
              if (m is InstanceInitializer) {
                this.HandleError(ctxEnsures, Error.ThrowsEnsuresOnConstructor);
                // ignore what was parsed
                exc.PostCondition = new Literal(true, null, ctx);
              }else{
                exc.PostCondition = ens;
              }
              mc.Ensures.Add(exc);
            }else{
              // throws E1, E2, ...;
//              exc.PostCondition = new Literal(true, null, ctx);
              mc.Ensures.Add(exc);

              while (this.currentToken == Token.Comma) {
                this.GetNextToken();
                exc = new EnsuresExceptional();
                exc.SourceContext = this.scanner.CurrentSourceContext;
                exc.Type = exc.TypeExpression = this.ParseTypeExpression(Identifier.Empty, followers|Token.Comma|ContractStart);
                exc.Variable = new Local(TypeExpressionFor("System", "Exception"));
                exc.Variable.SourceContext = ctx;
                exc.PostCondition = new Literal(true, null, ctx);
                mc.Ensures.Add(exc);
              }
            }

            finalPos = this.scanner.CurrentSourceContext.EndPos;
            swallowedSemicolonAlready= (this.currentToken == Token.Semicolon);
            this.SkipSemiColon(followers|ContractStart);
            n = exc;
            break;
          }

        }
        if (n != null) {
          n.SourceContext= ctx;
          n.SourceContext.EndPos = finalPos ;
        }
        m.SourceContext.EndPos = finalPos;
      }
      // What error to generate here?
      if (!followers[this.currentToken])
        this.SkipTo(followers);
      if (initialSourceContext.EndPos != this.scanner.CurrentSourceContext.EndPos) {
        // then a contract really was parsed
        m.Contract = mc;
      }
      if (this.currentToken != Token.EndOfFile) this.parsingStatement = savedParsingStatement;
    }
 public override EnsuresExceptional VisitEnsuresExceptional (EnsuresExceptional exceptional) {
   if (exceptional == null) return null;
   if (exceptional.PostCondition == null || exceptional.Variable == null) {
     return base.VisitEnsuresExceptional(exceptional);
   }
   // Create the scoping structure only if there is a user-defined variable to bind to
   // the exception and there is a condition. (This code was copied from VisitCatch.)
   exceptional.Type = this.VisitTypeReference(exceptional.Type);
   SourceContext sctx = exceptional.PostCondition.SourceContext;
   Scope savedScope = this.scope;
   Block b = new Block(new StatementList(new ExpressionStatement(exceptional.PostCondition)));
   Scope scope = this.scope = new BlockScope(savedScope, b);
   this.AddToAllScopes(this.scope);
   TrivialHashtable savedTargetFor = this.targetFor;
   TrivialHashtable targetFor = this.targetFor = new TrivialHashtable();
   IdentifierList labelList = this.labelList;
   int n = labelList.Count;
   for (int i = 0; i < n; i++) {
     Identifier label = labelList[i];
     targetFor[label.UniqueIdKey] = savedTargetFor[label.UniqueIdKey];
   }
   Identifier throwsId = exceptional.Variable as Identifier;
   if (throwsId != null) {
     Field f = new Field();
     f.DeclaringType = scope;
     f.Flags = FieldFlags.CompilerControlled;
     f.Name = throwsId;
     f.Type = exceptional.Type;
     scope.Members.Add(f);
     exceptional.Variable = new MemberBinding(new ImplicitThis(scope, 0), f, throwsId.SourceContext);
   }
   this.scope = scope;
   this.AddToAllScopes(this.scope);
   Declarer declarer = this.GetDeclarer();
   declarer.VisitBlock(b, scope, targetFor, labelList);
   b = base.VisitBlock(b);
   exceptional.PostCondition = new BlockExpression(b, SystemTypes.Boolean, sctx);
   this.scope = savedScope;
   this.targetFor = savedTargetFor;
   labelList.Count = n;
   return exceptional;
 }
Exemple #11
0
    public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional) {
      if (exceptional == null) return null;
      {
        #region Generate the runtime code for checking the postcondition
        Expression en = exceptional.PostCondition;
        if (en == null) return exceptional;
        StatementList exsuresStatements = new StatementList();
        Block exsuresBlock = new Block(exsuresStatements);
        exsuresBlock.HasLocals = true;

        // Code generation for postconditions needs to be such that the
        // data flow analysis will "see" the consequences. If the value
        // of the postcondition is assigned to a local, then the information
        // is lost.
        //
        // for the throws clause: throws (E e) ensures Q(e) 
        // generate:
        //
        // ... at beginning of all exceptional postconditions ...
        // ... generated in VisitMethod ...
        // catch (Exception caught_exception){
        //
        //     E e = caught_exception as E;
        //     if (e == null || en) goto L;
        //     throw new PostConditionException(...);
        //     L: nop
        //
        // ... at end of all exceptional postconditions ...
        // ... generated in VisitMethod ...
        // rethrow
        //
        // The reason for generating the if test this way is to avoid trying to branch out
        // of the catch block

        Block post_holds = new Block(new StatementList(new Statement(NodeType.Nop)));

        #region Evaluate the postcondition within a try block. If an exception happens during evaluation, throw a wrapped exception.
        bool noAllocationAllowed = this.currentMethod.GetAttribute(SystemTypes.BartokNoHeapAllocationAttribute) != null;
        Local exceptionDuringPostCondition = new Local(Identifier.For("SS$exceptionDuringPostCondition"),SystemTypes.Exception);
        Local objectExceptionDuringPostCondition = new Local(Identifier.For("SS$objectExceptionDuringPostCondition"),SystemTypes.Exception);
        Expression cond = exceptional.PostCondition;
        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 = new MemberBinding(null, SystemTypes.PreAllocatedExceptions.GetField(Identifier.For("InvalidContract")));
          ec3 = new MemberBinding(null, SystemTypes.PreAllocatedExceptions.GetField(Identifier.For("InvalidContract")));
        }
        else {
          MemberBinding excBinding2 = new MemberBinding(null, SystemTypes.EnsuresException.GetConstructor(SystemTypes.String, SystemTypes.Exception));
          MemberBinding excBinding3 = new MemberBinding(null, SystemTypes.EnsuresException.GetConstructor(SystemTypes.String));
          string msg2 = "Exception occurred during evaluation of postcondition '" + condition + "' in method '" + currentMethod.FullName + "'";
          ec2 = new Construct(excBinding2, new ExpressionList(new Literal(msg2, SystemTypes.String), exceptionDuringPostCondition));
          ec3 = new Construct(excBinding3, new ExpressionList(new Literal(msg2, SystemTypes.String)));
        }
        #endregion

        #region Throw an exception if the value of the postcondition was false
        Expression thrownException;
        if (noAllocationAllowed) {
          thrownException = new MemberBinding(null, SystemTypes.PreAllocatedExceptions.GetField(Identifier.For("Ensures")));
        }
        else {
          MemberBinding excBinding = new MemberBinding(null, SystemTypes.EnsuresException.GetConstructor(SystemTypes.String));
          Construct ec = new Construct(excBinding, new ExpressionList());
          string msg = "Exceptional postcondition '" + condition + "' violated from method '" + currentMethod.FullName + "'";
          ec.Operands.Add(new Literal(msg, SystemTypes.String));
          thrownException = ec;
        }
        Throw t2 = new Throw(thrownException,exceptional.SourceContext);
        #endregion


        exceptional.Variable = this.VisitExpression(exceptional.Variable);
        #region Create a local to hold the exception
        Local e;
        if (exceptional.Variable == null) {
          e = new Local(Identifier.Empty,exceptional.Type,exsuresBlock);
        } else {
          e = (Local)exceptional.Variable;
        }
        #endregion
        // E e = caught_exception as E;
        AssignmentStatement castToThrowType = new AssignmentStatement(e,
          new BinaryExpression(this.currentExceptionalTerminationException,
          new Literal(exceptional.Type, SystemTypes.Type), NodeType.Isinst, exceptional.Type));
        exsuresStatements.Add(castToThrowType);
        // e == null || Q(e)
        Expression disjunction = new BinaryExpression(
          new BinaryExpression(e, Literal.Null, NodeType.Eq),
          en,
          NodeType.LogicalOr);
        exsuresStatements.Add(new If(disjunction, new Block(new StatementList(new Branch(null, post_holds))), null));
        exsuresStatements.Add(t2);
        exsuresStatements.Add(post_holds);
        exsuresBlock = this.VisitBlock(exsuresBlock);

        this.currentContractExceptionalTerminationChecks.Add(exsuresBlock);
        #endregion
        return exceptional;
      }
    }
 public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional)
 {
     // since clousot doesn't handle exceptional post yet, we filter them out here.
     // TODO: refactor Ensures into two lists: normal and exceptional
     return(null);
 }
        public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional)
        {
            var result = base.VisitEnsuresExceptional(exceptional);

            result.UserMessage = (Expression) Visit(result.UserMessage);

            return result;
        }
 public EventingVisitor(Action<EnsuresExceptional> visitEnsuresExceptional) { VisitedEnsuresExceptional += visitEnsuresExceptional; } public event Action<EnsuresExceptional> VisitedEnsuresExceptional; public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional) { if (VisitedEnsuresExceptional != null) VisitedEnsuresExceptional(exceptional); return base.VisitEnsuresExceptional(exceptional); }
        protected override object VisitCall(Variable dest, Variable receiver, Method callee, ExpressionList arguments, bool virtcall, Statement stat, object arg)
        {
            ExposureState estate = (ExposureState)arg;

            if (callee.CciKind == Cci.CciMemberKind.FrameGuardGetter)
            {
                // associate dest with receiver, because unpack is going to happen with dest as receiver
                estate.AssignFrameFor(dest, receiver, callee.DeclaringType); // receiver could be a subtype of the type that the frame guard is for
            }
            else if (callee == UnpackMethod)
            {
                if (estate.IsFrameExposable(receiver))
                {
                    // BUGBUG: Using CopyVariable encodes the assumption that StartWritingTransitively returns itself!!! It may not!
                    estate.CopyVariable(receiver, dest);
                    estate.AssignFrameForExposed(dest);
                }
                else
                {
                    TypeNode t = estate.LowerBoundOfObjectPointedToByFrame(receiver);
                    if (t == null) // BUGBUG: is this the same as it being Top?
                    {
                        HandleError(stat, stat, Error.DontKnowIfCanExposeObject);
                    }
                    else
                    {
                        HandleError(stat, stat, Error.ExposingExposedObject);
                    }
                    return(null);
                }
            }
            else if (callee == PackMethod)
            {
                estate.AssignFrameForNotExposed(receiver);
            }
            else if (callee == IsExposableMethod)
            {
                estate.AssignFunctionLink(ExposureState.EqIsExposableId, dest, receiver);
            }
            else if (callee == IsExposedMethod)
            {
                estate.AssignEqIsExposed(dest, receiver);
            }
            else if (callee == AssertMethod)
            {
                Variable v = arguments[0] as Variable;
                if (v != null && estate.IsFalse(v))
                {
                    return(null);
                }
            }

            // Push possible exceptions to handlers.
            for (int i = 0; i < callee.Contract.Ensures.Count; i++)
            {
                EnsuresExceptional e = callee.Contract.Ensures[i] as EnsuresExceptional;
                if (e != null)
                {
                    ExposureState newnn = new ExposureState(estate);
                    newnn.currentException = e.Type;
                    ExposureChecker.PushExceptionState(ExposureChecker.currBlock, newnn);
                }
            }

            return(arg);
        }
 public virtual EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional1, EnsuresExceptional exceptional2) {
   if (exceptional1 == null) return null;
   if (exceptional2 == null) {
     exceptional1.PostCondition = this.VisitExpression(exceptional1.PostCondition, null);
     exceptional1.Type = this.VisitTypeReference(exceptional1.Type, null);
     exceptional1.Variable = this.VisitExpression(exceptional1.Variable, null);
   }else{
     exceptional1.PostCondition = this.VisitExpression(exceptional1.PostCondition, exceptional2.PostCondition);
     exceptional1.Type = this.VisitTypeReference(exceptional1.Type, exceptional2.Type);
     exceptional1.Variable = this.VisitExpression(exceptional1.Variable, exceptional2.Variable);
   }
   return exceptional1;
 }
Exemple #17
0
 public virtual EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional) {
   if (exceptional == null) return null;
   exceptional.PostCondition = this.VisitExpression(exceptional.PostCondition);
   exceptional.Type = this.VisitTypeReference(exceptional.Type);
   exceptional.Variable = this.VisitExpression(exceptional.Variable);
   return exceptional;
 }
Exemple #18
0
 public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional)
 {
   if (exceptional == null) return null;
   return base.VisitEnsuresExceptional((EnsuresExceptional)exceptional.Clone());
 }
 public override void VisitEnsuresExceptional(EnsuresExceptional exceptional)
 {
     this.checkingExceptionalPostcondition = true;
     base.VisitEnsuresExceptional(exceptional);
 }
        public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional)
        {
            if (exceptional == null) return null;

            var result = base.VisitEnsuresExceptional(exceptional);
            result.UserMessage = ExtractorVisitor.FilterUserMessage(this.targetMethod, result.UserMessage);
                
            return result;
        }
 public override void VisitEnsuresExceptional(EnsuresExceptional exceptional)
 {
     seenDup = false;
     base.VisitEnsuresExceptional(exceptional);
 }
 public override EnsuresExceptional VisitEnsuresExceptional(EnsuresExceptional exceptional)
 {
     // since clousot doesn't handle exceptional post yet, we filter them out here.
     // TODO: refactor Ensures into two lists: normal and exceptional
     return null;
 }