private List<Unit> instrumentIntentAddings(
      BiDiInterproceduralCFG<Unit, SootMethod> cfg,
      Unit unit,
      InvokeExpr sinkExpr,
      Set<ResultSourceInfo> sourceInfo) {
    if (isMethodInterComponentSink(sinkExpr.getMethod())) {
      SootMethod method = cfg.getMethodOf(unit);
      Body body = null;
      if (method.hasActiveBody()) body = method.retrieveActiveBody();
      else throw new RuntimeException("No body found!");

      Set<String> sourceCategories = getDataIdList(sourceInfo);

      final String hashSetType = "java.util.HashSet";
      List<Unit> generated = new ArrayList<Unit>();

      // HashSet initialization
      Local hashSetLocal = generateFreshLocal(body, RefType.v(hashSetType));
      NewExpr newExpr = Jimple.v().newNewExpr(RefType.v(hashSetType));
      AssignStmt assignStmt = Jimple.v().newAssignStmt(hashSetLocal, newExpr);
      generated.add(assignStmt);

      // constructor call
      SpecialInvokeExpr constructorCall =
          Jimple.v()
              .newSpecialInvokeExpr(
                  hashSetLocal,
                  Scene.v().getMethod("<java.util.HashSet: void <init>()>").makeRef());
      InvokeStmt constructorCallStmt = Jimple.v().newInvokeStmt(constructorCall);
      generated.add(constructorCallStmt);

      // add categories to HashSet
      for (String cat : sourceCategories) {
        InterfaceInvokeExpr addCall =
            Jimple.v()
                .newInterfaceInvokeExpr(
                    hashSetLocal,
                    Scene.v().getMethod("<java.util.Set: boolean add(java.lang.Object)>").makeRef(),
                    StringConstant.v(cat));
        InvokeStmt addCallStmt = Jimple.v().newInvokeStmt(addCall);
        generated.add(addCallStmt);
      }

      // get Intent
      Value intent = sinkExpr.getArg(0);
      List<Object> args = new ArrayList<Object>();
      args.add(RefType.v("android.content.Intent"));
      args.add(intent);
      args.add(RefType.v(hashSetType));
      args.add(hashSetLocal);
      StaticInvokeExpr sie =
          Instrumentation.createJimpleStaticInvokeExpr(
              Settings.INSTRUMENTATION_HELPER_JAVA, "addTaintInformationToIntent", args);
      InvokeStmt invStmt = Jimple.v().newInvokeStmt(sie);
      generated.add(invStmt);

      return generated;
    }
    return Collections.emptyList();
  }
  private boolean isInterComponentSourceCallback(
      ResultSourceInfo si, BiDiInterproceduralCFG<Unit, SootMethod> cfg) {
    if (isSourceInfoParameter(si)) {
      SootMethod sm = cfg.getMethodOf(si.getSource());

      if (entryPointCreator.getCallbackFunctions().containsKey(sm.getDeclaringClass())) {
        if (entryPointCreator
            .getCallbackFunctions()
            .get(sm.getDeclaringClass())
            .contains(sm.getSignature())) return true;
      }
    }

    return false;
  }
  /**
   * @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
  }