Esempio n. 1
0
 // when two control points merge.  Returns true if this state changed.
 public bool Join(FlowAnalysisLocalState other)
 {
     this.Merge();
     other.Merge();
     this.Reachable |= other.Reachable;
     return(this.Assigned.IntersectWith(other.Assigned));
 }
Esempio n. 2
0
        /// <summary>
        /// Visit a boolean condition expression, where we will be wanting AssignedWhenTrue and
        /// AssignedWhenFalse.
        /// </summary>
        /// <param name="node"></param>
        protected void VisitCondition(BoundExpression node)
        {
            Debug.Assert(!this.state.Assigned.IsNull);
            Visit(node);

            // We implement the foundational rules missing from the language specification:
            // v is "definitely assigned when true" after a constant expression whose value is false.
            // v is "definitely assigned when false" after a constant expression whose value is true.
            // These rules are to be added to the language specification.
            // It was the lack of these foundational rules that led to the invention of the concept
            // of "unreachable expression" in the native compiler.
            if (IsConstantTrue(node))
            {
                state.Merge();
                this.state = new FlowAnalysisLocalState(this.state.Reachable, this.state.Assigned, BitArray.AllSet(nextVariableSlot));
            }
            else if (IsConstantFalse(node))
            {
                state.Merge();
                this.state = new FlowAnalysisLocalState(this.state.Reachable, BitArray.AllSet(nextVariableSlot), this.state.Assigned);
            }
            else
            {
                state.Split();
            }
        }
Esempio n. 3
0
        public override object VisitConditionalOperator(BoundConditionalOperator node, object arg)
        {
            VisitCondition(node.Condition);
            var consequenceState = new FlowAnalysisLocalState(this.state.Reachable, this.state.AssignedWhenTrue);
            var alternativeState = new FlowAnalysisLocalState(this.state.Reachable, this.state.AssignedWhenFalse);

            this.state = consequenceState;
            Visit(node.Consequence);
            consequenceState = this.state;

            this.state = alternativeState;
            Visit(node.Alternative);
            alternativeState = this.state;

            if (IsConstantTrue(node.Condition))
            {
                this.state = consequenceState;
                // it may be a boolean state at this point.
            }
            else if (IsConstantFalse(node.Condition))
            {
                this.state = alternativeState;
                // it may be a boolean state at this point.
            }
            else
            {
                // is may not be a boolean state at this point (5.3.3.28)
                this.state = consequenceState;
                this.state.Join(alternativeState);
            }
            return(null);
        }
Esempio n. 4
0
        public override object VisitForStatement(BoundForStatement node, object arg)
        {
            VisitStatement(node.Initializer);
            LoopHead(node);
            bool isTrue;
            bool isFalse;

            if (node.Condition != null)
            {
                isFalse = IsConstantFalse(node.Condition);
                isTrue  = IsConstantTrue(node.Condition);
                VisitCondition(node.Condition);
            }
            else
            {
                isTrue     = true;
                isFalse    = false;
                this.state = new FlowAnalysisLocalState(this.state.Reachable, this.state.Assigned, BitArray.AllSet(nextVariableSlot));
            }
            var bodyState          = new FlowAnalysisLocalState(this.state.Reachable && !isFalse, this.state.AssignedWhenTrue);
            var breakState         = new FlowAnalysisLocalState(this.state.Reachable && !isTrue, this.state.AssignedWhenFalse);
            var oldPendingBranches = this.pendingBranches;

            this.pendingBranches = ArrayBuilder <PendingBranch> .GetInstance();

            this.state = bodyState;
            VisitStatement(node.Body);
            ResolveContinues(node.ContinueLabel);
            VisitStatement(node.Increment);
            LoopTail(node);
            ResolveBreaks(oldPendingBranches, breakState, node.BreakLabel);
            return(null);
        }
Esempio n. 5
0
        /// <summary>
        /// Return the flow analysis state associated with a label.
        /// </summary>
        /// <param name="label"></param>
        /// <returns></returns>
        FlowAnalysisLocalState?LabelState(LabelSymbol label)
        {
            FlowAnalysisLocalState?result;

            if (labels.TryGetValue(label, out result))
            {
                return(result);
            }

            result = FlowAnalysisLocalState.UnreachableState(nextVariableSlot);
            labels.Add(label, result);
            return(result);
        }
Esempio n. 6
0
        public override object VisitWhileStatement(BoundWhileStatement node, object arg)
        {
            // while (node.Condition) { node.Body; node.ContinueLabel: } node.BreakLabel:
            LoopHead(node);
            VisitCondition(node.Condition);
            var bodyState          = new FlowAnalysisLocalState(this.state.Reachable && !IsConstantFalse(node.Condition), this.state.AssignedWhenTrue);
            var breakState         = new FlowAnalysisLocalState(this.state.Reachable && !IsConstantTrue(node.Condition), this.state.AssignedWhenFalse);
            var oldPendingBranches = SavePending();

            this.state = bodyState;
            VisitStatement(node.Body);
            ResolveContinues(node.ContinueLabel);
            LoopTail(node);
            ResolveBreaks(oldPendingBranches, breakState, node.BreakLabel);
            return(null);
        }
Esempio n. 7
0
        public override object VisitDoStatement(BoundDoStatement node, object arg)
        {
            // do { statements; node.ContinueLabel: } while (node.Condition) node.BreakLabel:
            var oldPendingBranches = this.pendingBranches;

            this.pendingBranches = ArrayBuilder <PendingBranch> .GetInstance();

            LoopHead(node);
            VisitStatement(node.Body);
            ResolveContinues(node.ContinueLabel);
            VisitCondition(node.Condition);
            var breakState = new FlowAnalysisLocalState(this.state.Reachable && !IsConstantTrue(node.Condition), this.state.AssignedWhenFalse);

            this.state = new FlowAnalysisLocalState(this.state.Reachable && !IsConstantFalse(node.Condition), this.state.AssignedWhenTrue);
            LoopTail(node);
            ResolveBreaks(oldPendingBranches, breakState, node.BreakLabel);
            return(null);
        }
Esempio n. 8
0
        public override object VisitIfStatement(BoundIfStatement node, object arg)
        {
            // 5.3.3.5 If statements
            VisitCondition(node.Condition);
            var trueState  = new FlowAnalysisLocalState(this.state.Reachable && !IsConstantFalse(node.Condition), state.AssignedWhenTrue);
            var falseState = new FlowAnalysisLocalState(this.state.Reachable && !IsConstantTrue(node.Condition), state.AssignedWhenFalse);

            this.state = trueState;
            VisitStatement(node.Consequence);
            trueState  = this.state;
            this.state = falseState;
            if (node.Alternative != null)
            {
                VisitStatement(node.Alternative);
            }
            this.state.Join(trueState);
            return(null);
        }
Esempio n. 9
0
        /// <summary>
        /// Used to resolve break statements in each statement form that has a break statement
        /// (loops, switch).
        /// </summary>
        /// <param name="oldPendingBranches"></param>
        /// <param name="breakState"></param>
        /// <param name="breakLabel"></param>
        private void ResolveBreaks(ArrayBuilder <PendingBranch> oldPendingBranches, FlowAnalysisLocalState breakState, LabelSymbol breakLabel)
        {
            foreach (var pending in this.pendingBranches)
            {
                switch (pending.Branch.Kind)
                {
                case BoundKind.BreakStatement:
                    Debug.Assert((pending.Branch as BoundBreakStatement).Label == breakLabel);
                    breakState.Join(pending.State);
                    break;

                default:
                    oldPendingBranches.Add(pending);
                    break;
                }
            }

            this.pendingBranches.Free();
            this.pendingBranches = oldPendingBranches;
            this.state           = breakState;
        }
Esempio n. 10
0
 /// <summary>
 /// Set the current state to one that indicates that it is unreachable.
 /// </summary>
 protected void SetUnreachable()
 {
     this.state = FlowAnalysisLocalState.UnreachableState(this.nextVariableSlot);
 }
Esempio n. 11
0
        /// <summary>
        /// Perform a single pass of flow analysis.  Note that after this pass,
        /// this.backwardBranchChanged indicates if a further pass is required.
        /// </summary>
        protected virtual void Scan()
        {
            // the entry point of a method is assumed reachable
            state = FlowAnalysisLocalState.ReachableState();

            // label out parameters as not assigned.
            foreach (var parameter in method.Parameters)
            {
                if (parameter.RefKind == RefKind.Out)
                {
                    SetSlotState(MakeSlot(parameter), initiallyAssignedVariables != null && initiallyAssignedVariables.Contains(parameter));
                }
                else
                {
                    // this code has no effect except in the region analysis APIs, which assign
                    // variable slots to all parameters.
                    int slot = VariableSlot(parameter);
                    SetSlotState(slot, true);
                }
            }

            // TODO: if this is the body of an initial struct constructor, mark "this" as unassigned.
            this.backwardBranchChanged = false;
            if (this.Diagnostics != null)
            {
                this.Diagnostics.Free();
            }
            this.Diagnostics     = DiagnosticBag.GetInstance(); // clear reported diagnostics
            this.alreadyReported = BitArray.Empty;              // no variables yet reported unassigned
            VisitStatement(block);

            // check that each local variable is used somewhere (or warn if it isn't)
            foreach (var symbol in variableBySlot)
            {
                if (symbol != null && symbol.Kind == SymbolKind.Local && !readVariables.Contains(symbol))
                {
                    Diagnostics.Add(writtenVariables.Contains(symbol) ? ErrorCode.WRN_UnreferencedVarAssg : ErrorCode.WRN_UnreferencedVar, symbol.Locations[0], symbol.Name);
                }
            }

            // check that each out parameter is definitely assigned at the end of the method if
            // there's more than one location, then the method is partial and we prefer to report an
            // out parameter in partial method error
            if (method.Locations.Count == 1)
            {
                foreach (ParameterSymbol parameter in method.Parameters)
                {
                    if (parameter.RefKind == RefKind.Out)
                    {
                        var slot = VariableSlot(parameter);
                        if (!state.IsAssigned(slot))
                        {
                            ReportUnassignedOutParameter(parameter, null, method.Locations[0]);
                        }

                        foreach (PendingBranch returnBranch in pendingBranches)
                        {
                            if (!returnBranch.State.IsAssigned(slot))
                            {
                                ReportUnassignedOutParameter(parameter, returnBranch.Branch.Syntax, null);
                            }
                        }
                    }
                }
            }
            // TODO: handle "this" in struct constructor.
        }
Esempio n. 12
0
 // when two control points merge.  Returns true if this state changed.
 public bool Join(FlowAnalysisLocalState other)
 {
     this.Merge();
     other.Merge();
     this.Reachable |= other.Reachable;
     return this.Assigned.IntersectWith(other.Assigned);
 }
Esempio n. 13
0
        /// <summary>
        /// Used to resolve break statements in each statement form that has a break statement
        /// (loops, switch).
        /// </summary>
        /// <param name="oldPendingBranches"></param>
        /// <param name="breakState"></param>
        /// <param name="breakLabel"></param>
        private void ResolveBreaks(ArrayBuilder<PendingBranch> oldPendingBranches, FlowAnalysisLocalState breakState, LabelSymbol breakLabel)
        {
            foreach (var pending in this.pendingBranches)
            {
                switch (pending.Branch.Kind)
                {
                    case BoundKind.BreakStatement:
                        Debug.Assert((pending.Branch as BoundBreakStatement).Label == breakLabel);
                        breakState.Join(pending.State);
                        break;
                    default:
                        oldPendingBranches.Add(pending);
                        break;
                }
            }

            this.pendingBranches.Free();
            this.pendingBranches = oldPendingBranches;
            this.state = breakState;
        }
Esempio n. 14
0
        /// <summary>
        /// Visit a boolean condition expression, where we will be wanting AssignedWhenTrue and
        /// AssignedWhenFalse.
        /// </summary>
        /// <param name="node"></param>
        protected void VisitCondition(BoundExpression node)
        {
            Debug.Assert(!this.state.Assigned.IsNull);
            Visit(node);

            // We implement the foundational rules missing from the language specification:
            // v is "definitely assigned when true" after a constant expression whose value is false.
            // v is "definitely assigned when false" after a constant expression whose value is true.
            // These rules are to be added to the language specification.
            // It was the lack of these foundational rules that led to the invention of the concept
            // of "unreachable expression" in the native compiler.
            if (IsConstantTrue(node))
            {
                state.Merge();
                this.state = new FlowAnalysisLocalState(this.state.Reachable, this.state.Assigned, BitArray.AllSet(nextVariableSlot));
            }
            else if (IsConstantFalse(node))
            {
                state.Merge();
                this.state = new FlowAnalysisLocalState(this.state.Reachable, BitArray.AllSet(nextVariableSlot), this.state.Assigned);
            }
            else
            {
                state.Split();
            }
        }
Esempio n. 15
0
 /// <summary>
 /// Set the current state to one that indicates that it is unreachable.
 /// </summary>
 protected void SetUnreachable()
 {
     this.state = FlowAnalysisLocalState.UnreachableState(this.nextVariableSlot);
 }
Esempio n. 16
0
        /// <summary>
        /// Perform a single pass of flow analysis.  Note that after this pass,
        /// this.backwardBranchChanged indicates if a further pass is required.
        /// </summary>
        protected virtual void Scan()
        {
            // the entry point of a method is assumed reachable
            state = FlowAnalysisLocalState.ReachableState();

            // label out parameters as not assigned.
            foreach (var parameter in method.Parameters)
            {
                if (parameter.RefKind == RefKind.Out)
                {
                    SetSlotState(MakeSlot(parameter), initiallyAssignedVariables != null && initiallyAssignedVariables.Contains(parameter));
                }
                else
                {
                    // this code has no effect except in the region analysis APIs, which assign
                    // variable slots to all parameters.
                    int slot = VariableSlot(parameter);
                    SetSlotState(slot, true);
                }
            }

            // TODO: if this is the body of an initial struct constructor, mark "this" as unassigned.
            this.backwardBranchChanged = false;
            if (this.Diagnostics != null)
                this.Diagnostics.Free();
            this.Diagnostics = DiagnosticBag.GetInstance();  // clear reported diagnostics
            this.alreadyReported = BitArray.Empty;           // no variables yet reported unassigned
            VisitStatement(block);

            // check that each local variable is used somewhere (or warn if it isn't)
            foreach (var symbol in variableBySlot)
            {
                if (symbol != null && symbol.Kind == SymbolKind.Local && !readVariables.Contains(symbol))
                {
                    Diagnostics.Add(writtenVariables.Contains(symbol) ? ErrorCode.WRN_UnreferencedVarAssg : ErrorCode.WRN_UnreferencedVar, symbol.Locations[0], symbol.Name);
                }
            }

            // check that each out parameter is definitely assigned at the end of the method if
            // there's more than one location, then the method is partial and we prefer to report an
            // out parameter in partial method error
            if (method.Locations.Count == 1)
            {
                foreach (ParameterSymbol parameter in method.Parameters)
                {
                    if (parameter.RefKind == RefKind.Out)
                    {
                        var slot = VariableSlot(parameter);
                        if (!state.IsAssigned(slot))
                        {
                            ReportUnassignedOutParameter(parameter, null, method.Locations[0]);
                        }

                        foreach (PendingBranch returnBranch in pendingBranches)
                        {
                            if (!returnBranch.State.IsAssigned(slot))
                            {
                                ReportUnassignedOutParameter(parameter, returnBranch.Branch.Syntax, null);
                            }
                        }
                    }
                }
            }
            // TODO: handle "this" in struct constructor.
        }