private boolean callEdgesReasonable() {
   Set<VarNode> vars = contextSensitiveAssignEdges.keySet();
   for (VarNode node : vars) {
     ArraySet<AssignEdge> assigns = contextSensitiveAssignEdges.get(node);
     for (AssignEdge edge : assigns) {
       if (edge.isCallEdge()) {
         if (edge.getCallSite() == null) {
           G.v().out.println(edge + " is weird!!");
           return false;
         }
       }
     }
   }
   return true;
 }
 public Set<Integer> getVirtCallSitesForReceiver(LocalVarNode receiver) {
   return receiverToVirtCallSites.get(receiver);
 }
 public ArraySet<SootMethod> getCallSiteTargets(Integer callSite) {
   return callSiteToTargets.get(callSite);
 }
 public ArraySet<AssignEdge> getCallSiteEdges(Integer callSite) {
   return callSiteToEdges.get(callSite);
 }
 public Set<Integer> getCallSitesInvokingMethod(SootMethod method) {
   return callSitesInvokingMethod.get(method);
 }
 /**
  * @param method
  * @return
  */
 public ArraySet<Integer> getCallSitesInMethod(SootMethod method) {
   return callSitesInMethod.get(method);
 }
 public ArraySet<VarNode> getOutPortsForMethod(SootMethod method) {
   return methodToOutPorts.get(method);
 }
 public ArraySet<VarNode> getNodesForMethod(SootMethod method) {
   return methodToNodes.get(method);
 }
 /**
  * @param node
  * @return edges capturing assign flow <em>into</em> node
  */
 public ArraySet<AssignEdge> getAssignEdges(VarNode node) {
   return contextSensitiveAssignBarEdges.get(node);
 }
  public ContextSensitiveInfo(PAG pag) {
    // set up method to node map
    for (Iterator iter = pag.getVarNodeNumberer().iterator(); iter.hasNext(); ) {
      VarNode varNode = (VarNode) iter.next();
      if (varNode instanceof LocalVarNode) {
        LocalVarNode local = (LocalVarNode) varNode;
        SootMethod method = local.getMethod();
        assert method != null : local;
        methodToNodes.put(method, local);
        if (SootUtil.isRetNode(local)) {
          methodToOutPorts.put(method, local);
        }
        if (SootUtil.isParamNode(local)) {
          methodToInPorts.put(method, local);
        }
      }
    }
    int callSiteNum = 0;
    // first, add regular assigns
    Set assignSources = pag.simpleSources();
    for (Iterator iter = assignSources.iterator(); iter.hasNext(); ) {
      VarNode assignSource = (VarNode) iter.next();
      if (skipNode(assignSource)) {
        continue;
      }
      boolean sourceGlobal = assignSource instanceof GlobalVarNode;
      Node[] assignTargets = pag.simpleLookup(assignSource);
      for (int i = 0; i < assignTargets.length; i++) {
        VarNode assignTarget = (VarNode) assignTargets[i];
        if (skipNode(assignTarget)) continue;
        boolean isFinalizerNode = false;
        if (assignTarget instanceof LocalVarNode) {
          LocalVarNode local = (LocalVarNode) assignTarget;
          SootMethod method = local.getMethod();
          if (method.toString().indexOf("finalize()") != -1 && SootUtil.isThisNode(local)) {
            isFinalizerNode = true;
          }
        }
        boolean targetGlobal = assignTarget instanceof GlobalVarNode;
        AssignEdge assignEdge = new AssignEdge(assignSource, assignTarget);
        // handle weird finalizers
        if (isFinalizerNode) {
          assignEdge.setParamEdge();
          Integer callSite = new Integer(callSiteNum++);
          assignEdge.setCallSite(callSite);
        }
        addAssignEdge(assignEdge);
        if (sourceGlobal) {
          if (targetGlobal) {
            // System.err.println("G2G " + assignSource + " --> "
            // + assignTarget);
          } else {
            SootMethod method = ((LocalVarNode) assignTarget).getMethod();
            // don't want to include things assigned something that
            // is already an in port
            if (!methodToInPorts.get(method).contains(assignTarget)) {
              methodToInPorts.put(method, assignSource);
            }
          }
        } else {
          if (targetGlobal) {
            SootMethod method = ((LocalVarNode) assignSource).getMethod();
            // don't want to include things assigned from something
            // that
            // is already an out port
            if (!methodToOutPorts.get(method).contains(assignSource)) {
              methodToOutPorts.put(method, assignTarget);
            }
          }
        }
      }
    }
    // now handle calls
    HashMultiMap callAssigns = pag.callAssigns;
    PrintWriter callSiteWriter = null;
    if (PRINT_CALL_SITE_INFO) {
      try {
        callSiteWriter = new PrintWriter(new FileWriter("callSiteInfo"), true);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    for (Iterator iter = callAssigns.keySet().iterator(); iter.hasNext(); ) {
      InvokeExpr ie = (InvokeExpr) iter.next();
      Integer callSite = new Integer(callSiteNum++);
      callSiteToInvokedMethod.put(callSite, ie.getMethod());
      SootMethod invokingMethod = pag.callToMethod.get(ie);
      callSiteToInvokingMethod.put(callSite, invokingMethod);
      if (PRINT_CALL_SITE_INFO) {
        callSiteWriter.println(callSite + " " + callSiteToInvokingMethod.get(callSite) + " " + ie);
      }
      if (pag.virtualCallsToReceivers.containsKey(ie)) {
        LocalVarNode receiver = (LocalVarNode) pag.virtualCallsToReceivers.get(ie);
        assert receiver != null;
        virtCallSiteToReceiver.put(callSite, receiver);
        receiverToVirtCallSites.put(receiver, callSite);
      }
      Set curEdges = callAssigns.get(ie);
      for (Iterator iterator = curEdges.iterator(); iterator.hasNext(); ) {
        Pair callAssign = (Pair) iterator.next();
        VarNode src = (VarNode) callAssign.getO1();
        VarNode dst = (VarNode) callAssign.getO2();
        if (skipNode(src)) {
          continue;
        }
        ArraySet edges = getAssignBarEdges(src);
        AssignEdge edge = null;
        for (int i = 0; i < edges.size() && edge == null; i++) {
          AssignEdge curEdge = (AssignEdge) edges.get(i);
          if (curEdge.getDst() == dst) {
            edge = curEdge;
          }
        }
        assert edge != null : "no edge from " + src + " to " + dst;
        boolean edgeFromOtherCallSite = edge.isCallEdge();
        if (edgeFromOtherCallSite) {
          edge = new AssignEdge(src, dst);
        }
        edge.setCallSite(callSite);
        callSiteToEdges.put(callSite, edge);
        if (SootUtil.isParamNode(dst)) {
          // assert src instanceof LocalVarNode : src + " " + dst;
          edge.setParamEdge();
          SootMethod invokedMethod = ((LocalVarNode) dst).getMethod();
          callSiteToTargets.put(callSite, invokedMethod);
          callSitesInvokingMethod.put(invokedMethod, callSite);
          // assert src instanceof LocalVarNode : src + " NOT LOCAL";
          if (src instanceof LocalVarNode) {
            callSitesInMethod.put(((LocalVarNode) src).getMethod(), callSite);
          }
        } else if (SootUtil.isRetNode(src)) {
          edge.setReturnEdge();
          SootMethod invokedMethod = ((LocalVarNode) src).getMethod();
          callSiteToTargets.put(callSite, invokedMethod);
          callSitesInvokingMethod.put(invokedMethod, callSite);
          if (dst instanceof LocalVarNode) {
            callSitesInMethod.put(((LocalVarNode) dst).getMethod(), callSite);
          }
        } else {
          assert false : "weird call edge " + callAssign;
        }
        if (edgeFromOtherCallSite) {
          addAssignEdge(edge);
        }
      }
    }
    // System.err.println(callSiteNum + " call sites");
    assert callEdgesReasonable();
    if (PRINT_CALL_SITE_INFO) {
      callSiteWriter.close();
    }
    // assert assignEdgesWellFormed(pag) == null :
    // assignEdgesWellFormed(pag);

  }