protected ReferenceVariable arrayElementOfImpl(ReferenceVariable base) {
   VarNode l;
   if (base instanceof VarNode) {
     l = (VarNode) base;
   } else {
     FieldRefNode b = (FieldRefNode) base;
     l = pag.makeGlobalVarNode(b, b.getType());
     pag.addEdge(b, l);
   }
   return pag.makeFieldRefNode(l, ArrayElement.v());
 }
  protected void assignObjectToImpl(ReferenceVariable lhs, AbstractObject obj) {
    AllocNode objNode =
        pag.makeAllocNode(new Pair("AbstractObject", obj.getType()), obj.getType(), null);

    VarNode var;
    if (lhs instanceof FieldRefNode) {
      var = pag.makeGlobalVarNode(objNode, objNode.getType());
      pag.addEdge((Node) lhs, var);
    } else {
      var = (VarNode) lhs;
    }
    pag.addEdge(objNode, var);
  }
  @Override
  public Set<? extends IAllocNode> getPTSet(Value val, Context context) {
    // handle case for insensitive run
    if (k == 0) return getPTSetIns(val);

    final Set<AllocNode> allocNodes = new LinkedHashSet<AllocNode>();
    final Type filteringType = val.getType();

    PointsToSetInternal pts = null;

    try {
      if (val instanceof InstanceFieldRef) {
        final InstanceFieldRef ifr = (InstanceFieldRef) val;
        pts =
            (PointsToSetInternal)
                ptsProvider.reachingObjects(context, (Local) ifr.getBase(), ifr.getField());
      } else if (val instanceof ArrayRef) {
        ArrayRef arrayRef = (ArrayRef) val;
        pts =
            (PointsToSetInternal)
                ptsProvider.reachingObjectsOfArrayElement(
                    ptsProvider.reachingObjects(context, (Local) arrayRef.getBase()));
      } else if (val instanceof Local) {
        pts = (PointsToSetInternal) ptsProvider.reachingObjects(context, (Local) val);
      } else if (val instanceof StaticFieldRef) {
        SootField field = ((StaticFieldRef) val).getField();
        pts = (PointsToSetInternal) ptsProvider.reachingObjects(field);
      } else if (val instanceof NullConstant) {
        return allocNodes;
      } else {
        logger.error("Unknown reference type for insenstive search: {} {}", val, val.getClass());
        droidsafe.main.Main.exit(1);
      }

      // visit internal points to set and grab all allocnodes
      pts.forall(
          new P2SetVisitor() {
            public void visit(Node n) {
              if (typeManager.castNeverFails(n.getType(), filteringType))
                allocNodes.add((AllocNode) n);
            }
          });

    } catch (Exception e) {
      logger.info("Some sort of error getting context insensitive points to set for {}", val, e);
      // e.printStackTrace();
    }

    return allocNodes;
  }
  public Set<? extends IAllocNode> getPTSetOfArrayElement(IAllocNode allocNode) {
    final Set<AllocNode> ptSet = new LinkedHashSet<AllocNode>();
    if (!(allocNode.getType() instanceof ArrayType)) {
      logger.error(
          "Calling getPTSetOfArrayElement on non array type: {} with {}",
          allocNode,
          allocNode.getType());
    }

    final Type filteringType = ((ArrayType) allocNode.getType()).getElementType();

    HashPointsToSet pointsToSet = new HashPointsToSet(allocNode.getType(), ptsProvider);
    pointsToSet.add((AllocNode) allocNode);

    ((PointsToSetInternal) ptsProvider.reachingObjectsOfArrayElement(pointsToSet))
        .forall(
            new P2SetVisitor() {
              @Override
              public void visit(Node node) {
                if (typeManager.castNeverFails(node.getType(), filteringType))
                  ptSet.add((AllocNode) node);
              }
            });

    return (Set<? extends IAllocNode>) ptSet;
  }
 /** constructor, add edges to maps */
 public MatchEdges(PAG pag) {
   Iterator<VarNode> store_it = pag.storeSourcesIterator();
   // storeMap: store_src(VarNode) ----> store_targets(FieldRefNode)
   while (store_it.hasNext()) {
     // get the representative of the union
     VarNode from = ((VarNode) store_it.next()); // storeSrc, a
     Node[] storeTargets = pag.storeLookup(from);
     for (int i = 0; i < storeTargets.length; i++) {
       FieldRefNode storeTarget = (FieldRefNode) storeTargets[i]; // x.f
       VarNode storeTargetBase = storeTarget.getBase(); // x
       SparkField storeTargetField = storeTarget.getField(); // f
       String storeTargetFieldSig = ((SootField) storeTargetField).getSignature(); // f's signature
       // three inheritances of SparkField:
       // ArrayElement, Parm, and SootField
       if (storeTargetField instanceof SootField) {
         Iterator<FieldRefNode> load_it = pag.loadSourcesIterator();
         while (load_it.hasNext()) {
           FieldRefNode loadSrc = (FieldRefNode) load_it.next(); // y.f
           VarNode loadSrcBase = loadSrc.getBase(); // y
           SparkField loadSrcField = loadSrc.getField(); // f
           if (loadSrcField instanceof SootField) {
             // see whether x.f and y.f has the same offset of
             // the field
             String loadSrcFieldSig = ((SootField) loadSrcField).getSignature(); // f's signature
             if (loadSrcFieldSig.equals(storeTargetFieldSig)) {
               Node[] to = pag.loadLookup(loadSrc); // loadTargets
               for (int j = 0; j < to.length; j++) {
                 addMatchEdge(from, (VarNode) to[j]);
               }
             }
           }
         }
       }
     }
   }
 }
 @SuppressWarnings("unused")
 private String assignEdgesWellFormed(PAG pag) {
   for (Iterator iter = pag.getVarNodeNumberer().iterator(); iter.hasNext(); ) {
     VarNode v = (VarNode) iter.next();
     Set<AssignEdge> outgoingAssigns = getAssignBarEdges(v);
     for (AssignEdge edge : outgoingAssigns) {
       if (edge.getSrc() != v) return edge + " src should be " + v;
     }
     Set<AssignEdge> incomingAssigns = getAssignEdges(v);
     for (AssignEdge edge : incomingAssigns) {
       if (edge.getDst() != v) return edge + " dst should be " + v;
     }
   }
   return null;
 }
  @Override
  public Set<? extends IAllocNode> getPTSet(IAllocNode node, final SootField f) {
    if (f.isStatic()) {
      logger.error("Cannot call getPTSet(node, field) with static field: {}", f);
      droidsafe.main.Main.exit(1);
    }
    final Type filteringType = f.getType();

    final Set<AllocNode> allocNodes = new LinkedHashSet<AllocNode>();

    HashPointsToSet pointsToSet = new HashPointsToSet(node.getType(), ptsProvider);
    pointsToSet.add((AllocNode) node);

    ((PointsToSetInternal) ptsProvider.reachingObjects(pointsToSet, f))
        .forall(
            new P2SetVisitor() {
              @Override
              public void visit(Node node) {
                if (typeManager.castNeverFails(node.getType(), filteringType))
                  allocNodes.add((AllocNode) node);
              }
            });

    /*
    PointsToSetInternal bases = (PointsToSetInternal)ptsProvider.getSetFactory().newSet(node.getType(), ptsProvider);
    bases.add(node);

    final PointsToSetInternal pts = ptsProvider.getSetFactory().newSet(
        (f instanceof SootField) ? ((SootField)f).getType() : null, ptsProvider );
    bases.forall( new P2SetVisitor() {
        public final void visit( Node n ) {
            Node nDotF = ((AllocNode) n).dot( f );
            if(nDotF != null) pts.addAll( nDotF.getP2Set(), null );
        }} );

    //visit internal points to set and grab all allocnodes
    pts.forall(new P2SetVisitor() {
        public void visit(Node n) {
            allocNodes.add((AllocNode)n);
        }
    });
     */
    return (Set<? extends IAllocNode>) allocNodes;
  }
  @Override
  protected void runInternal() {
    // don't print crap to screen!
    G.v().out = new PrintStream(NullOutputStream.NULL_OUTPUT_STREAM);
    Scene.v().loadDynamicClasses();

    setSparkPointsToAnalysis();

    // other passes can print crap now
    G.v().out = System.out;

    ptsProvider = (PAG) Scene.v().getPointsToAnalysis();

    typeManager = ptsProvider.getTypeManager();

    // cache the call graph
    callGraph = Scene.v().getCallGraph();

    createNewToAllocMap();

    /*
    for (SootMethod method : getReachableMethods()) {
        Set<MethodOrMethodContext> mcs = getMethodContexts(method);
        if (mcs.size() > 30)
            System.out.println(method + " " + mcs.size());
    }
     */

    // dumpReachablesAndAllocNodes();
    // dumpCallGraphReachablesCSV();
    // dumpOutdegreesCSV();

    if (Config.v().dumpPta) {
      dumpPTA(Project.v().getOutputDir() + File.separator + "pta.txt");
    }

    if (Config.v().dumpCallGraph) {
      // dumpCallGraph(Project.v().getOutputDir() + File.separator + "callgraph.dot");
      String fileName = String.format("callgraph%d.txt", runCount++);
      dumpTextGraph(Project.v().getOutputDir() + File.separator + fileName);
    }

    // System.out.println(SparkEvaluator.v().toString());
  }
  /** Create the bi map of NewExpr <-> AllocNode */
  private void createNewToAllocMap() {
    newToAllocNodeMap = HashBiMap.create();
    allAllocNodes = new LinkedHashSet<AllocNode>();

    Map<SootClass, Integer> nodeCount = new LinkedHashMap<SootClass, Integer>();

    int realSize = 0;

    for (AllocNode node : ptsProvider.getAllocNodes()) {
      if (!(node instanceof InsensitiveAllocNode)) {
        logger.error("Found non-insensitive node in ptsProvider.getAllocNodes()");
        droidsafe.main.Main.exit(1);
      }

      InsensitiveAllocNode insNode = (InsensitiveAllocNode) node;

      newToAllocNodeMap.put(node.getNewExpr(), insNode);
      realSize++;
      allAllocNodes.add(node);

      // countNode(nodeCount, node);

      for (Map.Entry<Context, ObjectSensitiveAllocNode> entry :
          insNode.getContextNodeMap().entrySet()) {
        allAllocNodes.add(entry.getValue());
        // countNode(nodeCount, node);
      }
    }

    System.out.println("Alloc node size (insensitive objects): " + realSize);

    /* used to print a sorted list of alloc nodes created
    Map<SootClass, Integer> sortedNodeCount = SootUtils.sortByValue(nodeCount);
    for (Map.Entry<SootClass, Integer> entry : sortedNodeCount.entrySet()) {
        System.out.println(entry.getValue() + " " + entry.getKey());
    }
     */
  }
  private void dumpReachablesAndAllocNodes() {
    try {
      FileWriter fw =
          new FileWriter(Project.v().getOutputDir() + File.separator + "spark-dump.log");

      fw.write("# Reachable Method Contexts:\n\n");

      for (MethodOrMethodContext momc : getReachableMethodContexts()) {
        fw.write(momc + "\n\n");
      }

      fw.write("\n\n# AllocNodes: \n\n");
      Iterator<AllocNode> nodes = ptsProvider.getAllocNodeNumberer().iterator();
      while (nodes.hasNext()) {
        AllocNode node = nodes.next();
        fw.write(node + "\n\n");
      }

      fw.close();

    } catch (IOException e) {

    }
  }
 protected void assignImpl(ReferenceVariable lhs, ReferenceVariable rhs) {
   pag.addEdge((Node) rhs, (Node) lhs);
 }
 protected void throwExceptionImpl(AbstractObject obj) {
   AllocNode objNode =
       pag.makeAllocNode(new Pair("AbstractObject", obj.getType()), obj.getType(), null);
   pag.addEdge(objNode, pag.nodeFactory().caseThrow());
 }
  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);

  }
 protected ReferenceVariable staticFieldImpl(String className, String fieldName) {
   SootClass c = RefType.v(className).getSootClass();
   SootField f = c.getFieldByName(fieldName);
   return pag.makeGlobalVarNode(f, f.getType());
 }
 protected ReferenceVariable newInstanceOfImpl(ReferenceVariable cls) {
   return pag.nodeFactory().caseNewInstance((VarNode) cls);
 }
 protected ReferenceVariable tempFieldImpl(String fieldsig) {
   return pag.makeGlobalVarNode(new Pair("tempField", fieldsig), RefType.v("java.lang.Object"));
 }
 protected ReferenceVariable tempVariableImpl() {
   return pag.makeGlobalVarNode(
       new Pair("TempVar", new Integer(++G.v().SparkNativeHelper_tempVar)),
       RefType.v("java.lang.Object"));
 }
 @Override
 public boolean isPointer(Value val) {
   return (ptsProvider.findGlobalVarNode(val) != null
       || ptsProvider.findLocalVarNode(val) != null);
 }
 @Override
 public boolean isLegalCast(Type objType, Type refType) {
   return ptsProvider.getTypeManager().castNeverFails(objType, refType);
 }
 protected ReferenceVariable tempLocalVariableImpl(SootMethod method) {
   return pag.makeLocalVarNode(
       new Pair("TempVar", new Integer(++G.v().SparkNativeHelper_tempVar)),
       RefType.v("java.lang.Object"),
       method);
 }