コード例 #1
0
        private StatementList GetContractClumpFromMoveNext(Method iteratorMethod, Method moveNext,
            ContractNodes contractNodes, StatementList contractInitializer, out SourceContext defaultSourceContext,
            ref HelperMethods.StackDepthTracker dupStackTracker,
            out AssumeBlock originalContractPosition)
        {
            Contract.Requires(moveNext != null);
            Contract.Requires(moveNext.Body != null);
            Contract.Requires(moveNext.Body.Statements != null);
            Contract.Requires(contractInitializer != null);
            Contract.Requires(iteratorMethod != null);

            var linkerVersion = 0;
            if (iteratorMethod.DeclaringType != null && iteratorMethod.DeclaringType.DeclaringModule != null)
            {
                linkerVersion = iteratorMethod.DeclaringType.DeclaringModule.LinkerMajorVersion;
            }

            var initialState = moveNext.IsAsync ? -1 : 0;
            moveNext.MoveNextStartState = initialState;
            originalContractPosition = null;
            int statementIndex;

            Contract.Assume(moveNext.Body != null);
            Contract.Assume(moveNext.Body.Statements != null);

            int blockIndex = ContractStartInMoveNext(this.contractNodes, moveNext, out statementIndex, iteratorMethod);

            Contract.Assert(statementIndex >= 0, "should follow from the postcondiiton");

            if (blockIndex < 0)
            {
                // Couldn't find state 0 in MoveNext method
                // This can happen if the iterator is trivial (like yield break; )
                defaultSourceContext = default(SourceContext);
                return null;
            }

            int beginning = blockIndex; // the block number in the body of movenext
            int sbeginning = statementIndex; // the statement no. in the beginnning block after the preamble
            int blast = -1;

            // the block number in the body of movenext, of the last block where there is a contract call
            int slast = -1; // the statement no. in the blast block

            // Next we move sbeginning past the preamble area
            sbeginning = MovePastPreamble(iteratorMethod, moveNext, beginning, sbeginning, contractInitializer,
                contractNodes, ref dupStackTracker);

            Contract.Assert(moveNext.Body != null, "should be provable");
            Contract.Assert(moveNext.Body.Statements != null, "should be provable");

            if (sbeginning < 0 ||
                !this.FindLastBlockWithContracts(moveNext.Body.Statements, beginning, out blast, out slast))
            {
                if (verbose)
                {
                    if (moveNext.Name != null)
                    {
                        Console.WriteLine("Method {0} doesnt have a contract method invocation at the right place.", moveNext.Name.Name);
                    }
                }

                defaultSourceContext = default(SourceContext);
                return null;
            }

            Block methodBody = moveNext.Body;
            Block lastBlock = methodBody.Statements[blast] as Block;
            SourceContext lastContractSourceContext;

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

            // TODO: check the clump is not in a try-catch block. 

            originalContractPosition = new AssumeBlock(new StatementList());
            StatementList result = HelperMethods.ExtractClump(
                moveNext.Body.Statements, beginning, sbeginning, blast,
                slast, assumeBlock: originalContractPosition);

            defaultSourceContext = lastContractSourceContext;
            return result;
        }
コード例 #2
0
        internal static StatementList ExtractClump(StatementList blocks, int firstBlockIndex, int firstStmtIndex,
            int lastBlockIndex, int lastStmtIndex, AssumeBlock assumeBlock = null)
        {
            Contract.Requires(blocks != null);
            Contract.Requires(firstBlockIndex >= 0);
            Contract.Requires(firstStmtIndex >= 0);

            Contract.Ensures(Contract.Result<StatementList>().Count == lastBlockIndex - firstBlockIndex + 1);
            Contract.Ensures(blocks[firstBlockIndex] == Contract.OldValue(blocks[firstBlockIndex]));

            StatementList clump = new StatementList();

            // first extract the tail of the first block into a new block.
            Block oldFirstBlock = (Block) blocks[firstBlockIndex];
            Block newFirstBlock = new Block(new StatementList());
            
            if (oldFirstBlock != null)
            {
                var count = firstBlockIndex == lastBlockIndex ? lastStmtIndex + 1 : oldFirstBlock.Statements.Count;
                for (int stmtIndex = firstStmtIndex; stmtIndex < count; stmtIndex++)
                {
                    var stmt = oldFirstBlock.Statements[stmtIndex];
                    newFirstBlock.Statements.Add(stmt);
                    
                    if (stmt == null) continue;

                    oldFirstBlock.Statements[stmtIndex] = assumeBlock;
                    assumeBlock = null;
                }
            }

            clump.Add(newFirstBlock);
            
            var currentBlockIndex = firstBlockIndex + 1;
            
            if (currentBlockIndex > lastBlockIndex) return clump;

            // setup info about forwarding branches to new last full block
            Block newLastBlock = null;

            var lastFullBlock = lastBlockIndex - 1;
            var oldLastBlock = (Block) blocks[lastBlockIndex];
            
            if (oldLastBlock != null && lastStmtIndex == oldLastBlock.Statements.Count - 1)
            {
                // last block is also fully used.
                lastFullBlock = lastBlockIndex;
            }
            else
            {
                newLastBlock = new Block(new StatementList());

                // check if first block had a branch
                if (newFirstBlock != null && newFirstBlock.Statements != null && newFirstBlock.Statements.Count > 0)
                {
                    // check if we need to adjust branch to last block
                    var branch = newFirstBlock.Statements[newFirstBlock.Statements.Count - 1] as Branch;
                    if (branch != null && branch.Target != null && branch.Target.UniqueKey == oldLastBlock.UniqueKey)
                    {
                        branch.Target = newLastBlock;
                    }
                }
            }

            // Next extract full blocks between currentBlockIndex and including lastFullBlock
            for (; currentBlockIndex <= lastFullBlock; currentBlockIndex++)
            {
                var block = (Block) blocks[currentBlockIndex];

                // don't skip null blocks since context relies on number
                clump.Add(block);

                if (block == null) continue;
                
                blocks[currentBlockIndex] = assumeBlock;
                assumeBlock = null;
                
                if (newLastBlock != null && block.Statements != null && block.Statements.Count > 0)
                {
                    // check if we need to adjust branch to last block
                    var branch = block.Statements[block.Statements.Count - 1] as Branch;
                    if (branch != null && branch.Target != null && branch.Target.UniqueKey == oldLastBlock.UniqueKey)
                    {
                        branch.Target = newLastBlock;
                    }
                }
            }

            // next, if last block wasn't full, we have a new last block, extract the prefix
            if (newLastBlock != null)
            {
                for (int i = 0; i < lastStmtIndex + 1; i++)
                {
                    newLastBlock.Statements.Add(oldLastBlock.Statements[i]);
                    oldLastBlock.Statements[i] = assumeBlock;
                    assumeBlock = null;
                }

                clump.Add(newLastBlock);
            }

            return clump;
        }
コード例 #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);
                }
            }
        }