Beispiel #1
0
        void ChangeEdgeStatus(ControlFlowEdge edge, DefiniteAssignmentStatus newStatus)
        {
            DefiniteAssignmentStatus oldStatus = edgeStatus[edge];

            if (oldStatus == newStatus)
            {
                return;
            }
            // Ensure that status can cannot change back to CodeUnreachable after it once was reachable.
            // Also, don't ever use AssignedAfter... for statements.
            if (newStatus == DefiniteAssignmentStatus.CodeUnreachable ||
                newStatus == DefiniteAssignmentStatus.AssignedAfterFalseExpression ||
                newStatus == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
            {
                throw new InvalidOperationException();
            }
            // Note that the status can change from DefinitelyAssigned
            // back to PotentiallyAssigned as unreachable input edges are
            // discovered to be reachable.

            edgeStatus[edge] = newStatus;
            DefiniteAssignmentNode targetNode = (DefiniteAssignmentNode)edge.To;

            if (analyzedRangeStart <= targetNode.Index && targetNode.Index <= analyzedRangeEnd)
            {
                // TODO: potential optimization: visit previously unreachable nodes with higher priority
                // (e.g. use Deque and enqueue previously unreachable nodes at the front, but
                // other nodes at the end)
                nodesWithModifiedInput.Enqueue(targetNode);
            }
        }
Beispiel #2
0
        public void Analyze(string variable, DefiniteAssignmentStatus initialStatus = DefiniteAssignmentStatus.PotentiallyAssigned, CancellationToken cancellationToken = default(CancellationToken))
        {
            this.analysisCancellationToken = cancellationToken;
            this.variableName = variable;
            try {
                // Reset the status:
                unassignedVariableUses.Clear();
                foreach (DefiniteAssignmentNode node in allNodes)
                {
                    node.NodeStatus = DefiniteAssignmentStatus.CodeUnreachable;
                    foreach (ControlFlowEdge edge in node.Outgoing)
                    {
                        edgeStatus[edge] = DefiniteAssignmentStatus.CodeUnreachable;
                    }
                }

                ChangeNodeStatus(allNodes[analyzedRangeStart], initialStatus);
                // Iterate as long as the input status of some nodes is changing:
                while (nodesWithModifiedInput.Count > 0)
                {
                    DefiniteAssignmentNode   node        = nodesWithModifiedInput.Dequeue();
                    DefiniteAssignmentStatus inputStatus = DefiniteAssignmentStatus.CodeUnreachable;
                    foreach (ControlFlowEdge edge in node.Incoming)
                    {
                        inputStatus = MergeStatus(inputStatus, edgeStatus[edge]);
                    }
                    ChangeNodeStatus(node, inputStatus);
                }
            } finally {
                this.analysisCancellationToken = CancellationToken.None;
                this.variableName = null;
            }
        }
Beispiel #3
0
 static DefiniteAssignmentStatus CleanSpecialValues(DefiniteAssignmentStatus status)
 {
     if (status == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
     {
         return(DefiniteAssignmentStatus.PotentiallyAssigned);
     }
     else if (status == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
     {
         return(DefiniteAssignmentStatus.PotentiallyAssigned);
     }
     else
     {
         return(status);
     }
 }
Beispiel #4
0
        public void Analyze(string variable, CancellationToken cancellationToken, DefiniteAssignmentStatus initialStatus = DefiniteAssignmentStatus.PotentiallyAssigned)
        {
            this.analysisCancellationToken = cancellationToken;
            this.variableName = variable;
            try {
                // Reset the status:
                unassignedVariableUses.Clear();
                foreach (DefiniteAssignmentNode node in allNodes)
                {
                    node.NodeStatus = DefiniteAssignmentStatus.CodeUnreachable;
                    foreach (ControlFlowEdge edge in node.Outgoing)
                    {
                        edgeStatus[edge] = DefiniteAssignmentStatus.CodeUnreachable;
                    }
                }

                ChangeNodeStatus(allNodes[analyzedRangeStart], initialStatus);
                // Iterate as long as the input status of some nodes is changing:
                int       count           = 0;
                const int HACK_POLL_COUNT = 0x00200000;
                while (nodesWithModifiedInput.Count > 0)
                {
                    if (count++ >= HACK_POLL_COUNT)
                    {
                        this.analysisCancellationToken.ThrowIfCancellationRequested();
                        count = 0;
                    }
                    DefiniteAssignmentNode   node        = nodesWithModifiedInput.Dequeue();
                    DefiniteAssignmentStatus inputStatus = DefiniteAssignmentStatus.CodeUnreachable;
                    foreach (ControlFlowEdge edge in node.Incoming)
                    {
                        inputStatus = MergeStatus(inputStatus, edgeStatus[edge]);
                    }
                    ChangeNodeStatus(node, inputStatus);
                }
            } finally {
                this.analysisCancellationToken = CancellationToken.None;
                this.variableName = null;
            }
        }
Beispiel #5
0
        static DefiniteAssignmentStatus MergeStatus(DefiniteAssignmentStatus a, DefiniteAssignmentStatus b)
        {
            // The result will be DefinitelyAssigned if at least one incoming edge is DefinitelyAssigned and all others are unreachable.
            // The result will be DefinitelyUnassigned if at least one incoming edge is DefinitelyUnassigned and all others are unreachable.
            // The result will be Unreachable if all incoming edges are unreachable.
            // Otherwise, the result will be PotentiallyAssigned.

            if (a == b)
            {
                return(a);
            }
            else if (a == DefiniteAssignmentStatus.CodeUnreachable)
            {
                return(b);
            }
            else if (b == DefiniteAssignmentStatus.CodeUnreachable)
            {
                return(a);
            }
            else
            {
                return(DefiniteAssignmentStatus.PotentiallyAssigned);
            }
        }
Beispiel #6
0
        void ChangeNodeStatus(DefiniteAssignmentNode node, DefiniteAssignmentStatus inputStatus)
        {
            if (node.NodeStatus == inputStatus)
            {
                return;
            }
            node.NodeStatus = inputStatus;
            DefiniteAssignmentStatus outputStatus;

            switch (node.Type)
            {
            case ControlFlowNodeType.StartNode:
            case ControlFlowNodeType.BetweenStatements:
                if (node.NextStatement is IfElseStatement)
                {
                    // Handle if-else as a condition node
                    goto case ControlFlowNodeType.LoopCondition;
                }
                if (inputStatus == DefiniteAssignmentStatus.DefinitelyAssigned)
                {
                    // There isn't any way to un-assign variables, so we don't have to check the expression
                    // if the status already is definitely assigned.
                    outputStatus = DefiniteAssignmentStatus.DefinitelyAssigned;
                }
                else
                {
                    outputStatus = CleanSpecialValues(node.NextStatement.AcceptVisitor(visitor, inputStatus));
                }
                break;

            case ControlFlowNodeType.EndNode:
                outputStatus = inputStatus;
                if (node.PreviousStatement.Role == TryCatchStatement.FinallyBlockRole &&
                    (outputStatus == DefiniteAssignmentStatus.DefinitelyAssigned || outputStatus == DefiniteAssignmentStatus.PotentiallyAssigned))
                {
                    TryCatchStatement tryFinally = (TryCatchStatement)node.PreviousStatement.Parent;
                    // Changing the status on a finally block potentially changes the status of all edges leaving that finally block:
                    foreach (ControlFlowEdge edge in allNodes.SelectMany(n => n.Outgoing))
                    {
                        if (edge.IsLeavingTryFinally && edge.TryFinallyStatements.Contains(tryFinally))
                        {
                            DefiniteAssignmentStatus s = edgeStatus[edge];
                            if (s == DefiniteAssignmentStatus.PotentiallyAssigned)
                            {
                                ChangeEdgeStatus(edge, outputStatus);
                            }
                        }
                    }
                }
                break;

            case ControlFlowNodeType.LoopCondition:
                ForeachStatement foreachStmt = node.NextStatement as ForeachStatement;
                if (foreachStmt != null)
                {
                    outputStatus = CleanSpecialValues(foreachStmt.InExpression.AcceptVisitor(visitor, inputStatus));
                    if (foreachStmt.VariableName == this.variableName)
                    {
                        outputStatus = DefiniteAssignmentStatus.DefinitelyAssigned;
                    }
                    break;
                }
                else
                {
                    Debug.Assert(node.NextStatement is IfElseStatement || node.NextStatement is WhileStatement || node.NextStatement is ForStatement || node.NextStatement is DoWhileStatement);
                    Expression condition = node.NextStatement.GetChildByRole(AstNode.Roles.Condition);
                    if (condition.IsNull)
                    {
                        outputStatus = inputStatus;
                    }
                    else
                    {
                        outputStatus = condition.AcceptVisitor(visitor, inputStatus);
                    }
                    foreach (ControlFlowEdge edge in node.Outgoing)
                    {
                        if (edge.Type == ControlFlowEdgeType.ConditionTrue && outputStatus == DefiniteAssignmentStatus.AssignedAfterTrueExpression)
                        {
                            ChangeEdgeStatus(edge, DefiniteAssignmentStatus.DefinitelyAssigned);
                        }
                        else if (edge.Type == ControlFlowEdgeType.ConditionFalse && outputStatus == DefiniteAssignmentStatus.AssignedAfterFalseExpression)
                        {
                            ChangeEdgeStatus(edge, DefiniteAssignmentStatus.DefinitelyAssigned);
                        }
                        else
                        {
                            ChangeEdgeStatus(edge, CleanSpecialValues(outputStatus));
                        }
                    }
                    return;
                }

            default:
                throw new InvalidOperationException();
            }
            foreach (ControlFlowEdge edge in node.Outgoing)
            {
                ChangeEdgeStatus(edge, outputStatus);
            }
        }