private static boolean isSimpleCopy(Unit u) {
   if (!(u instanceof DefinitionStmt)) return false;
   DefinitionStmt defstmt = (DefinitionStmt) u;
   if (!(defstmt.getRightOp() instanceof Local)) return false;
   if (!(defstmt.getLeftOp() instanceof Local)) return false;
   return true;
 }
  private Map<Pair<Unit, Set<String>>, Set<Unit>> createProvidesConfigMap(
      Collection<Unit> unitsInSelection, LiftedReachingDefinitions reachingDefinitions, Body body) {
    Map<Pair<Unit, Set<String>>, Set<Unit>> unitConfigurationMap =
        new HashMap<Pair<Unit, Set<String>>, Set<Unit>>();

    for (Unit unitFromSelection : unitsInSelection) {
      if (unitFromSelection instanceof DefinitionStmt) {
        /*
         * exclude definitions when it's $temp on the leftOp.
         */
        DefinitionStmt definition = (DefinitionStmt) unitFromSelection;
        Local leftOp = (Local) definition.getLeftOp();
        if (leftOp.getName().charAt(0) == '$') {
          continue;
        }

        System.out.println("Definition:" + definition);

        // for every unit in the body...
        Iterator<Unit> iterator = body.getUnits().snapshotIterator();
        while (iterator.hasNext()) {
          Unit nextUnit = iterator.next();
          LiftedFlowSet<Collection<Set<Object>>> liftedFlowAfter =
              reachingDefinitions.getFlowAfter(nextUnit);
          Set<String>[] configurations = liftedFlowAfter.getConfigurations();
          FlowSet[] lattices = liftedFlowAfter.getLattices();
          // and for every configuration...
          for (int configurationIndex = 0;
              configurationIndex < configurations.length;
              configurationIndex++) {
            FlowSet flowSet = lattices[configurationIndex];
            Set<String> currConfiguration = configurations[configurationIndex];
            FeatureTag nextUnitTag = (FeatureTag) nextUnit.getTag("FeatureTag");

            // if the unit belongs to the current configuration...
            if (nextUnitTag.belongsToConfiguration(currConfiguration)) {

              // if the definition reaches this unit...
              if (flowSet.contains(definition)) {
                List<ValueBox> useBoxes = nextUnit.getUseBoxes();
                for (ValueBox vbox : useBoxes) {
                  /*
                   * and the definition is used, add to the
                   * map...
                   */
                  if (vbox.getValue().equivTo(leftOp)) {
                    Pair<Unit, Set<String>> currentPair =
                        new Pair<Unit, Set<String>>(definition, currConfiguration);
                    Set<Unit> unitConfigurationReachesSet = unitConfigurationMap.get(currentPair);

                    if (unitConfigurationReachesSet == null) {
                      unitConfigurationReachesSet = new HashSet<Unit>();
                      unitConfigurationReachesSet.add(nextUnit);
                      unitConfigurationMap.put(currentPair, unitConfigurationReachesSet);
                    } else {
                      unitConfigurationReachesSet.add(nextUnit);
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return unitConfigurationMap;
  }
  /**
   * Generate Policy Enforcement Point (PEP) for Unit 'unit'.
   *
   * @param unit
   * @param invExpr
   * @param body
   * @param dataFlowAvailable
   * @param assignmentStatement
   * @return
   */
  private List<Unit> generatePolicyEnforcementPoint(
      Unit unit,
      InvokeExpr invExpr,
      Body body,
      int dataFlowAvailable,
      boolean assignmentStatement) {

    log.debug("Dataflow available: " + dataFlowAvailable);

    List<Unit> generated = new ArrayList<Unit>(); // store all new units that are generated

    String methodSignature = invExpr.getMethod().getSignature();
    EventInformation eventInfo = allEventInformation.get(methodSignature);
    String eventName = eventInfo.getEventName();

    Set<Pair<Integer, String>> allParameterInformation = eventInfo.getParameterInformation();

    // This list containts types and parameters that are used to build the
    // invoke expression to "isStmtExecutionAllowed':
    //
    // java.lang.String   "eventName"
    // IntType            "dataFlowAvailable"
    // java.lang.Object[] "parameters"
    //
    List<Object> parameterForHelperMethod = new ArrayList<Object>();
    List<Object> categories = new ArrayList<Object>();

    // add event name information
    Type eventNameType = RefType.v("java.lang.String");
    parameterForHelperMethod.add(eventNameType);
    StringConstant eventNameConstant = StringConstant.v(eventName);
    parameterForHelperMethod.add(eventNameConstant);

    // add information about dataflow availability
    parameterForHelperMethod.add(IntType.v());
    parameterForHelperMethod.add(IntConstant.v(dataFlowAvailable));

    // add information about parameters
    parameterForHelperMethod.add(getParameterArrayType());
    List<Value> paramValues = new ArrayList<Value>();

    for (Pair<Integer, String> parameterInfo : allParameterInformation) {
      paramValues.add(StringConstant.v("param" + parameterInfo.getLeft() + "value"));
      paramValues.add(invExpr.getArg(parameterInfo.getLeft()));
    }

    Pair<Value, List<Unit>> arrayRefAndInstrumentation = generateParameterArray(paramValues, body);

    generated.addAll(arrayRefAndInstrumentation.getRight());

    parameterForHelperMethod.add(arrayRefAndInstrumentation.getLeft());

    // Generate PEP call to the PDP. Store the result send by the PDP to 'resultPDPLocal'
    // Pseudo code looks like this:
    //
    // resultPDPLocal = isStmtExecutionAllowed(eventName, dataFlowAvailable, parameters);
    //
    StaticInvokeExpr sie =
        Instrumentation.createJimpleStaticInvokeExpr(
            Settings.INSTRUMENTATION_HELPER_JAVA,
            "isStmtExecutionAllowed",
            parameterForHelperMethod);

    Local resultPDPLocal = generateFreshLocal(body, soot.IntType.v());
    AssignStmt asssCondition = Jimple.v().newAssignStmt(resultPDPLocal, sie);
    generated.add(asssCondition);

    for (Unit u : generated) {
      System.out.println("isStmt gen: " + u);
    }

    if (assignmentStatement) {
      // If the method call before which the PEP in inserted is an assignment statement of
      // the form "resultPDPLocal = originalCallThatIsChecked()", generate a new assignment
      // statement that stores a default value to "resultPDPLocal" if the PDP does not
      // allow the call of method originalCallThatIsChecked().
      //
      // Pseudo-code:
      //
      // if(resultPDPLocal == 0) goto dummyLabel:
      // result = originalCallThatIsChecked();
      // goto dummyLabel2:
      // dummyLabel:
      // result = dummyValue (i.e., 0 for IntType, false for BooleanType, ...)
      // dummyLabel2:
      // nop
      //

      if (unit instanceof DefinitionStmt) {
        DefinitionStmt defStmt = (DefinitionStmt) unit;

        Value pepCondition = Jimple.v().newEqExpr(resultPDPLocal, IntConstant.v(0));

        // insert nop
        Unit label2Nop = Jimple.v().newNopStmt();
        body.getUnits().insertAfter(label2Nop, unit);

        // insert result = dummyValue
        Unit dummyStatement = createCorrectDummyAssignment((Local) defStmt.getLeftOp());
        body.getUnits().insertAfter(dummyStatement, unit);
        log.debug("insert c: " + dummyStatement);

        // insert goto dummyLabel2:
        body.getUnits().insertAfter(Jimple.v().newGotoStmt(label2Nop), unit);

        IfStmt ifStmt = Jimple.v().newIfStmt(pepCondition, dummyStatement);
        generated.add(ifStmt);
      } else {
        throw new RuntimeException(
            "error: expected DefinitionStmt got " + unit + " -> " + unit.getClass());
      }

    } else {
      // If the method call before which the PEP in inserted is a call statement of
      // the form "originalCallThatIsChecked()", generate a new nop statement
      // to jump to if the PDP does not allow the call of method originalCallThatIsChecked().
      //
      // Pseudo-code:
      //
      // if(resultPDPLocal == 0) goto nopLabel:
      // result = originalCallThatIsChecked();
      // nopLabel:
      // nop
      //
      Value pepCondition = Jimple.v().newEqExpr(resultPDPLocal, IntConstant.v(0));

      NopStmt nopStmt = Jimple.v().newNopStmt();
      body.getUnits().insertAfter(nopStmt, unit);
      log.debug("insert d: " + nopStmt);

      IfStmt ifStmt = Jimple.v().newIfStmt(pepCondition, nopStmt);

      generated.add(ifStmt);
    }

    return generated;
  }
  /**
   * @param cfg
   * @param sink
   * @param assignmentStatement
   */
  private void instrumentSourceToSinkConnections(
      BiDiInterproceduralCFG<Unit, SootMethod> cfg,
      ResultSinkInfo sink,
      boolean assignmentStatement) {
    sourceSinkConnectionCounter += 1;

    // loop through the sinks
    for (ResultSinkInfo key : results.getResults().keySet()) {

      log.debug("compare: " + key);
      log.debug("     to: " + sink);

      // if the current sink is the sink at the unit tagged with 'sink'
      if (key.equals(sink)) {

        // loop through the sources
        for (ResultSourceInfo si : results.getResults().get(key)) {

          Stmt stmt = si.getSource();
          SootMethod sm = cfg.getMethodOf(stmt);
          Body body = sm.retrieveActiveBody();

          // Source instrumentation. The three type categories for the source are:
          // - callback
          // - ICC source method (i.e., Intent.getExtras())
          // - not a callback and not an ICC source method (i.e., getLine1Number())
          //
          if (isInterComponentSourceCallback(si, cfg)) {
            throw new RuntimeException("Callbacks as sources are not supported right now");
          } else if (isInterComponentSourceNoCallback(si, cfg)) {
            // only invoke expression are treated here
            if (stmt.containsInvokeExpr()) {
              // only statements that return a android.os.Bundle are currently supported
              if (stmt instanceof DefinitionStmt) {
                DefinitionStmt defStmt = (DefinitionStmt) stmt;
                Value leftValue = defStmt.getLeftOp();

                if (leftValue.getType().equals(RefType.v("android.os.Bundle"))) {
                  List<Object> args = new ArrayList<Object>();
                  args.add(IntType.v());
                  args.add(IntConstant.v(sourceSinkConnectionCounter));
                  args.add(RefType.v("android.os.Bundle"));
                  args.add(leftValue);
                  InvokeExpr invExpr =
                      Instrumentation.createJimpleStaticInvokeExpr(
                          Settings.INSTRUMENTATION_HELPER_JAVA,
                          "registerNewSourceSinkConnection",
                          args);
                  InvokeStmt invStmt = Jimple.v().newInvokeStmt(invExpr);

                  Unit instrumentationPoint = null;
                  if (stmt instanceof IdentityStmt) {
                    instrumentationPoint = getLastIdentityStmt(body);
                  } else {
                    instrumentationPoint = stmt;
                  }
                  body.getUnits().insertAfter(invStmt, instrumentationPoint);
                  log.debug("insert a: " + invStmt);
                } else {
                  System.err.println("We do only support android.os.Bundle right now!");
                }
              }
            }
          } else {

            String sourceCat = getSourceCategory(si);
            if (sourceCat != null) {
              List<Object> args = new ArrayList<Object>();
              args.add(IntType.v());
              args.add(IntConstant.v(sourceSinkConnectionCounter));
              args.add(RefType.v("java.lang.String"));
              args.add(StringConstant.v(sourceCat));
              InvokeExpr invExpr =
                  Instrumentation.createJimpleStaticInvokeExpr(
                      Settings.INSTRUMENTATION_HELPER_JAVA,
                      "registerNewSourceSinkConnection",
                      args);
              InvokeStmt invStmt = Jimple.v().newInvokeStmt(invExpr);

              Unit instrumentationPoint = null;
              if (stmt instanceof IdentityStmt) instrumentationPoint = getLastIdentityStmt(body);
              else instrumentationPoint = stmt;
              body.getUnits().insertAfter(invStmt, instrumentationPoint);
              log.debug("insert b: " + invStmt);
            }
          }

          // sink instrumentation
          if (sink.getSink().containsInvokeExpr()) {
            Body bodyOfSink = cfg.getMethodOf(key.getSink()).getActiveBody();
            InvokeExpr invExpr = sink.getSink().getInvokeExpr();
            List<Unit> generated = new ArrayList<Unit>();
            generated.addAll(
                instrumentIntentAddings(cfg, stmt, invExpr, results.getResults().get(key)));

            EventInformation sinkEventInfo =
                allEventInformation.get(invExpr.getMethod().getSignature());
            EventInformation sourceEventInfo =
                allEventInformation.get(si.getSource().getInvokeExpr().getMethod().getSignature());

            generated.addAll(
                generatePolicyEnforcementPoint(
                    key.getSink(),
                    invExpr,
                    bodyOfSink,
                    sourceSinkConnectionCounter,
                    assignmentStatement));

            log.debug("body with data flow:\n" + body);
            for (Unit u : generated) {
              log.debug("gen: " + u);
            }

            if (sinkEventInfo.isInstrumentAfterStatement())
              bodyOfSink.getUnits().insertAfter(generated, key.getSink());
            else bodyOfSink.getUnits().insertBefore(generated, key.getSink());
          } else throw new RuntimeException("Double-Check the assumption");
        } // loop through the sources
      } // if the sink at the unit is the current sink
    } // loop through the sinks
  }