예제 #1
0
        internal BitArray AssignedWhenFalse; // used only for boolean states

        public FlowAnalysisLocalState(bool reachable, BitArray assigned)
        {
            this.Reachable = reachable;
            this.Assigned = assigned;
            Debug.Assert(!assigned.IsNull);
            this.AssignedWhenTrue = this.AssignedWhenFalse = BitArray.Null;
        }
 public void UnionWith(BitArray other)
 {
     int l = other.bits.Length;
     if (l > this.bits.Length)
         Array.Resize(ref bits, l + 1);
     for (int i = 0; i < l; i++)
         this.bits[i] |= other.bits[i];
 }
 public bool IntersectWith(BitArray other)
 {
     bool anyChanged = false;
     int l = other.bits.Length;
     if (l > this.bits.Length)
         Array.Resize(ref bits, l + 1);
     for (int i = 0; i < l; i++)
     {
         var thisBits = this.bits;
         var oldV = thisBits[i];
         var newV = oldV & other.bits[i];
         if (newV != oldV) {
             thisBits[i] = newV;
             anyChanged = true;
         }
     }
     return anyChanged;
 }
예제 #4
0
 /// <summary>
 /// Turn this state into a non-conditional state (i.e. not to be used for control-flow).
 /// </summary>
 public void Merge()
 {
     if (!this.Assigned.IsNull)
         return;
     this.Assigned = this.AssignedWhenTrue;
     this.Assigned.IntersectWith(this.AssignedWhenFalse);
     this.AssignedWhenFalse = AssignedWhenTrue = BitArray.Null;
 }
예제 #5
0
 /// <summary>
 /// Turn this state into a conditional (boolean) state, to be used for control-flow.
 /// </summary>
 public void Split()
 {
     if (this.Assigned.IsNull)
         return;
     this.AssignedWhenTrue = this.Assigned.Clone();
     this.AssignedWhenFalse = this.Assigned;
     this.Assigned = BitArray.Null;
 }
예제 #6
0
 protected virtual void Free()
 {
     Diagnostics.Free();
     Diagnostics = null;
     pendingBranches.Free();
     pendingBranches = null;
     this.alreadyReported = BitArray.Null;
 }
예제 #7
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.
        }