Exemplo n.º 1
0
        private ISet <Variable> ProcessStatement(ISet <Variable> unavailable, IPStmt statement)
        {
            Contract.Requires(statement != null);
            switch (statement)
            {
            case CompoundStmt compoundStmt:
                unavailable = compoundStmt.Statements.Aggregate(unavailable, ProcessStatement);
                break;

            case AssertStmt assertStmt:
                unavailable = ProcessExpr(unavailable, assertStmt.Assertion);
                break;

            case PrintStmt printStmt:
                unavailable = ProcessArgList(printStmt.Args, unavailable, ArgOptions.SwapNotAllowed);
                break;

            case ReturnStmt returnStmt:
                if (returnStmt.ReturnValue != null)
                {
                    unavailable = ProcessExpr(unavailable, returnStmt.ReturnValue);
                }

                break;

            case AssignStmt assignStmt:
                unavailable = ProcessExpr(unavailable, assignStmt.Value);
                if (assignStmt.Location is VariableAccessExpr assignAccess)
                {
                    unavailable.Remove(assignAccess.Variable);
                }
                else
                {
                    unavailable = ProcessExpr(unavailable, assignStmt.Location);
                }

                break;

            case MoveAssignStmt moveAssignStmt:
                if (moveAssignStmt.FromVariable.Role.Equals(VariableRole.Field))
                {
                    throw handler.MovedField(moveAssignStmt);
                }

                unavailable.Add(moveAssignStmt.FromVariable);

                if (moveAssignStmt.ToLocation is VariableAccessExpr moveAssignAccess)
                {
                    unavailable.Remove(moveAssignAccess.Variable);
                }
                else
                {
                    unavailable = ProcessExpr(unavailable, moveAssignStmt.ToLocation);
                }

                break;

            case SwapAssignStmt swapAssignStmt:
                if (swapAssignStmt.NewLocation is VariableAccessExpr swapAssignAccess)
                {
                    if (unavailable.Contains(swapAssignAccess.Variable))
                    {
                        throw handler.SwapAssignUnavailable(swapAssignStmt, swapAssignAccess.Variable);
                    }
                }
                else
                {
                    unavailable = ProcessExpr(unavailable, swapAssignStmt.NewLocation);
                }

                if (unavailable.Contains(swapAssignStmt.OldLocation))
                {
                    throw handler.SwapAssignUnavailable(swapAssignStmt, swapAssignStmt.OldLocation);
                }

                break;

            case InsertStmt insertStmt:
                unavailable = ProcessExpr(unavailable, insertStmt.Variable);
                unavailable = ProcessExpr(unavailable, insertStmt.Index);
                unavailable = ProcessExpr(unavailable, insertStmt.Value);
                break;

            case RemoveStmt removeStmt:
                unavailable = ProcessExpr(unavailable, removeStmt.Variable);
                unavailable = ProcessExpr(unavailable, removeStmt.Value);
                break;

            case WhileStmt whileStmt:
                unavailable = ProcessExpr(unavailable, whileStmt.Condition);
                // process running the body twice. on the first go, the loop can potentially
                // relinquish additional variables on the second go, either the body will use
                // one of these variables and throw or reach a fixed point since all paths are
                // considered simultaneously. Then, we continue our overapproximation by taking
                // the union of no runs and one or more runs.
                var bodyUnavailable =
                    ProcessStatement(new HashSet <Variable>(unavailable), whileStmt.Body);
                bodyUnavailable = ProcessExpr(bodyUnavailable, whileStmt.Condition);
                // TODO: more efficient way of doing this?
                bodyUnavailable = ProcessStatement(bodyUnavailable, whileStmt.Body);
                bodyUnavailable = ProcessExpr(bodyUnavailable, whileStmt.Condition);
                unavailable.UnionWith(bodyUnavailable);
                break;

            case IfStmt ifStmt:
                unavailable = ProcessExpr(unavailable, ifStmt.Condition);
                var thenUnavailable =
                    ProcessStatement(new HashSet <Variable>(unavailable), ifStmt.ThenBranch);
                var elseUnavailable =
                    ProcessStatement(new HashSet <Variable>(unavailable), ifStmt.ElseBranch);
                thenUnavailable.UnionWith(elseUnavailable);
                unavailable = thenUnavailable;
                break;

            case CtorStmt ctorStmt:
                unavailable = ProcessArgList(ctorStmt.Arguments, unavailable, ArgOptions.SwapNotAllowed);
                break;

            case FunCallStmt funCallStmt:
                unavailable = ProcessArgList(funCallStmt.ArgsList, unavailable);
                funCallStmts.Add(funCallStmt);
                break;

            case RaiseStmt raiseStmt:
                unavailable = ProcessExpr(unavailable, raiseStmt.PEvent);
                unavailable = ProcessArgList(raiseStmt.Payload, unavailable, ArgOptions.SwapNotAllowed);
                break;

            case SendStmt sendStmt:
                unavailable = ProcessExpr(unavailable, sendStmt.MachineExpr);
                unavailable = ProcessExpr(unavailable, sendStmt.Evt);
                unavailable = ProcessArgList(sendStmt.Arguments, unavailable, ArgOptions.SwapNotAllowed);
                break;

            case AnnounceStmt announceStmt:
                unavailable = ProcessExpr(unavailable, announceStmt.PEvent);
                if (announceStmt.Payload != null)
                {
                    unavailable = ProcessExpr(unavailable, announceStmt.Payload);
                }

                break;

            case GotoStmt gotoStmt:
                if (gotoStmt.Payload != null)
                {
                    unavailable = ProcessExpr(unavailable, gotoStmt.Payload);
                }

                break;

            case ReceiveStmt receiveStmt:
                var postUnavailable = new HashSet <Variable>();
                var caseVariables   = new HashSet <Variable>();
                foreach (var recvCase in receiveStmt.Cases)
                {
                    var caseUnavailable =
                        ProcessStatement(new HashSet <Variable>(unavailable), recvCase.Value.Body);
                    postUnavailable.UnionWith(caseUnavailable);
                    caseVariables.UnionWith(recvCase.Value.Signature.Parameters);
                }

                unavailable = postUnavailable;
                unavailable.ExceptWith(caseVariables);
                break;

            case PopStmt _:
            case NoStmt _:
                // nothing to check
                break;

            default:
                throw handler.InternalError(statement.SourceLocation,
                                            new ArgumentOutOfRangeException(nameof(statement)));
            }

            return(unavailable);
        }