/// <summary>
    /// For the possible receiver v, check if it is nonnull. if no, file an proper
    /// error/warning.
    /// </summary>
    private void CheckReceiver(Statement stat, Variable v, ExposureState estate)
    {
      Node offendingNode = v;
      if (v == null) return;

      if(estate.IsNotExposed(v))
      {
        HandleError(stat, offendingNode, Error.WritingPackedObject, v.Name.Name);
        //estate.AssignExposed(v);
      }
      else if(!estate.IsExposed(v))
      {
        HandleError(stat, offendingNode, Error.WritingPackedObject, v.Name.Name);
        //estate.AssumeNonNull(v);
      }
    }
    protected override object VisitCall(Variable dest, Variable receiver, Method callee, ExpressionList arguments, bool virtcall, Statement stat, object arg) {
      ExposureState estate=(ExposureState)arg;

      if (callee.CciKind == Cci.CciMemberKind.FrameGuardGetter){
        // associate dest with receiver, because unpack is going to happen with dest as receiver
        estate.AssignFrameFor(dest,receiver,callee.DeclaringType); // receiver could be a subtype of the type that the frame guard is for
      }else if (callee == UnpackMethod){
        if(estate.IsFrameExposable(receiver)) {
          // BUGBUG: Using CopyVariable encodes the assumption that StartWritingTransitively returns itself!!! It may not!
          estate.CopyVariable(receiver,dest);
          estate.AssignFrameForExposed(dest);
        }else{
          TypeNode t = estate.LowerBoundOfObjectPointedToByFrame(receiver);
          if (t == null){ // BUGBUG: is this the same as it being Top?
            HandleError(stat, stat, Error.DontKnowIfCanExposeObject);
          }else{
            HandleError(stat, stat, Error.ExposingExposedObject);
          }
          return null;
        }
      }else if (callee == PackMethod){
        estate.AssignFrameForNotExposed(receiver);
      }else if (callee == IsExposableMethod){
        estate.AssignFunctionLink(ExposureState.EqIsExposableId,dest,receiver);
      }else if (callee == IsExposedMethod){
        estate.AssignEqIsExposed(dest,receiver);
      }else if (callee == AssertMethod){
        Variable v = arguments[0] as Variable;
        if (v != null && estate.IsFalse(v))
          return null;
      }

      // Push possible exceptions to handlers.
      for(int i=0;i<callee.Contract.Ensures.Count;i++){
        EnsuresExceptional e=callee.Contract.Ensures[i] as EnsuresExceptional;
        if(e!=null){
          ExposureState newnn=new ExposureState(estate);
          newnn.currentException=e.Type;
          ExposureChecker.PushExceptionState(ExposureChecker.currBlock,newnn);
        }
      }

      return arg;
    }
    /// <summary>
    /// Implementation of visit Block. It is called from run.
    /// 
    /// It calls VisitStatement.
    /// </summary>
    /// <param name="block"></param>
    /// <param name="stateOnEntry"></param>
    /// <returns></returns>
    protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) {
      Debug.Assert(block!=null);

      currBlock=block;

      Analyzer.Write("---------block: "+block.UniqueId+";");
      Analyzer.Write("   Exit:");
      foreach (CfgBlock b in block.NormalSuccessors)
        Analyzer.Write(b.UniqueId+";");
      if (block.UniqueSuccessor!=null)
        Analyzer.Write("   FallThrough: "+block.UniqueSuccessor+";");
      if (block.ExceptionHandler!=null)
        Analyzer.Write("   ExHandler: "+block.ExceptionHandler.UniqueId+";");
      Analyzer.WriteLine("");

      ExposureState newState;
      if(stateOnEntry==null)
        newState=new ExposureState(typeSystem);
      else
        newState=new ExposureState((ExposureState)stateOnEntry);
//      if (block.ExceptionHandler!=null)
//        this.PushExceptionState(block,newState);
      return base.VisitBlock (block, newState);
    }
    /// <summary>
    /// It split exceptions for current handler and the next chained handler.
    /// 
    /// It will:
    /// 
    ///   If the exception is completely intercepted by current handler, the
    ///   exception will be consumed.
    ///   
    ///   If the exception caught but not completely, both current handler and 
    ///   the next handler will take the states.
    ///   
    ///   If the exception is irrelevant to current caught, the next handler 
    ///   will take over the state. Current handler is then bypassed.
    /// </summary>
    /// <param name="handler"></param>
    /// <param name="currentHandlerState"></param>
    /// <param name="nextHandlerState"></param>
    protected override void SplitExceptions(CfgBlock handler, ref IDataFlowState currentHandlerState, out IDataFlowState nextHandlerState) {

      Debug.Assert(currentHandlerState!=null,"Internal error in NonNull Analysis");

      ExposureState state = (ExposureState)currentHandlerState;

      if(handler==null || handler.Length==0){
        nextHandlerState=null;
        return;
      }

      if(handler[0] is Unwind){
        nextHandlerState=null;
        currentHandlerState=null;
        return;
      }

      Debug.Assert(handler[0] is Catch, "Exception Handler does not starts with Catch");
      
      Debug.Assert(state.currentException!=null,"No current exception to handle");
      
      Catch c=(Catch)handler[0];

      if(handler.ExceptionHandler!=null && 
        !state.currentException.IsAssignableTo(c.Type)) {
        nextHandlerState = state;;
      }
      else {
        nextHandlerState=null;
      }

      // Compute what trickles through to the next handler
      //  and what sticks to this handler.
      if(state.currentException.IsAssignableTo(c.Type)) {
        // everything sticks 
        nextHandlerState = null;
      }
      else if (c.Type.IsAssignableTo(state.currentException)) {
        // c sticks, rest goes to next handler
        nextHandlerState = state;

        // copy state to modify the currentException
        state = new ExposureState(state);
        state.currentException = c.Type;
        currentHandlerState = state;
      }else {
        // nothing stick all goes to next handler
        nextHandlerState = state;
        currentHandlerState = null;
      }
      return;
    }
    /// <summary>
    /// Refines the given state according to the knowledge stored in the egraph about sv
    /// 
    /// In addition, the state can be null when the knowledge is inconsistent.
    /// </summary>
    /// <param name="cv">symbolic value we assume to be non-null (true)</param>
    /// <param name="state">state if sv is non-null (true)</param>
    private static void AssumeTrue(ISymValue cv, ref ExposureState state) {

      if (state == null) return;

      foreach(EGraphTerm t in state.egraph.EqTerms(cv)){
        ISymValue op = t.Args[0];
        if (t.Function == ExposureState.EqIsExposedId){
          // EqIsExposed(op) == true, therefore op *is* exposed
          state.AssignFrameForExposed(op);
        }else if (t.Function == ExposureState.EqIsExposableId){
          state.AssignFrameForExposable(op);
        }
      }
    }
    /// <summary>
    /// Refines the given state according to the knowledge stored in the egraph about sv
    /// 
    /// In addition, the state can be null when the knowledge is inconsistent.
    /// </summary>
    /// <param name="cv">symbolic value we assume to be false</param>
    private static void AssumeFalse(ISymValue cv, ref ExposureState state) {
      if (state == null) return;

      foreach(EGraphTerm t in state.egraph.EqTerms(cv)) {
        if (t.Function == ExposureState.EqIsExposedId) {
          // EqIsExposed(op) == false, therefore op is *not* exposed
          ISymValue op = t.Args[0];
          
//          state.AssignFrameForNotExposed(op);
          ISymValue guardedObject = state.egraph[FrameFor, op];
          state.egraph[guardedObject] = Lattice.AVal.Top; // BUGBUG?? If it isn't exposed at this frame, then what is it?
        }
      }
    }
    public void RefineBranchInformation(Variable cond, out ExposureState trueState, out ExposureState falseState) {

      ISymValue cv = this.egraph[cond];

      trueState = new ExposureState(this);
      falseState = new ExposureState(this);

      AssumeTrue(cv, ref trueState);
      AssumeFalse(cv, ref falseState);
    }
    /// <summary>
    /// Returns null, if result of Join is the same as atMerge.
    /// </summary>
    public static ExposureState Join(ExposureState atMerge, ExposureState incoming, CfgBlock joinPoint) {

      bool unchanged;
      IEGraph merged = atMerge.egraph.Join(incoming.egraph, joinPoint, out unchanged);

      TypeNode currentException = (atMerge.currentException != null)?
        ((incoming.currentException != null)? CciHelper.LeastCommonAncestor(atMerge.currentException, incoming.currentException) : null) : null;

      if (atMerge.currentException != currentException || !unchanged) {
        return new ExposureState(merged, currentException, atMerge.typeSystem);
      }
      return null;
    }
 public ExposureState(ExposureState old){
   this.typeSystem = old.typeSystem;
   this.egraph = (IEGraph)old.egraph.Clone();  
   this.currentException = old.currentException;
 }