@Override
  public KillGenInfo propagateReturnFlow(
      Trackable trackable, Unit callSite, SootMethod calleeMethod, Unit exitStmt, Unit returnSite) {
    boolean isSeedMethod = seedMethods.contains(context.icfg.getMethodOf(exitStmt));

    if (!(exitStmt instanceof ReturnStmt))
      return new KillGenInfo(isSeedMethod, Collections.<Trackable>emptyList());

    Taint taint = (Taint) trackable;
    ReturnStmt returnStmt = (ReturnStmt) exitStmt;
    Value retVal = AnalysisUtil.getForwardsBase(returnStmt.getOp());
    if (isSeedMethod && AnalysisUtil.maybeSameLocation(taint.value, retVal)) {
      SootMethod m = context.icfg.getMethodOf(returnStmt);
      if (AnalysisUtil.methodMayBeCallableFromApplication(m)) {
        if (!trackable.getPayload().isEmpty()) {
          context.reporter.reportTrackable(new Report(context, taint, exitStmt));
        }
      }
    }
    return new KillGenInfo(isSeedMethod, Collections.<Trackable>emptyList());
  }
  @Override
  public Type appliesInternal(AndroidMethod method) {
    SootMethod sm = getSootMethod(method);

    // We are only interested in getters and setters
    if (!sm.getName().startsWith("get") && !sm.getName().startsWith("set"))
      return Type.NOT_SUPPORTED;
    String baseName = sm.getName().substring(3);
    String getterName = "get" + baseName;
    String setterName = "set" + baseName;

    try {
      // Find the getter and the setter
      SootMethod getter =
          getSootMethod(new AndroidMethod(getterName, "", sm.getDeclaringClass().getName()));
      SootMethod setter =
          getSootMethod(new AndroidMethod(setterName, "", sm.getDeclaringClass().getName()));
      if (getter == null || setter == null) return Type.FALSE;

      if (!setter.isConcrete() || !getter.isConcrete()) return Type.NOT_SUPPORTED;

      Body bodyGetter = null;
      try {
        bodyGetter = getter.retrieveActiveBody();
      } catch (Exception ex) {
        return Type.NOT_SUPPORTED;
      }

      // Find the local that gets returned
      Local returnLocal = null;
      for (Unit u : bodyGetter.getUnits())
        if (u instanceof ReturnStmt) {
          ReturnStmt ret = (ReturnStmt) u;
          if (ret.getOp() instanceof Local) {
            returnLocal = (Local) ret.getOp();
            break;
          }
        }
      if (returnLocal == null) return Type.FALSE;

      // Find where the local is assigned a value in the code
      List<FieldRef> accessPath = new ArrayList<FieldRef>();
      Local returnBase = returnLocal;
      while (returnBase != null)
        for (Unit u : bodyGetter.getUnits()) {
          if (u instanceof AssignStmt) {
            AssignStmt assign = (AssignStmt) u;
            if (assign.getLeftOp().equals(returnBase))
              if (assign.getRightOp() instanceof InstanceFieldRef) {
                InstanceFieldRef ref = (InstanceFieldRef) assign.getRightOp();
                accessPath.add(0, ref);
                returnBase = (Local) ref.getBase();
                break;
              } else returnBase = null;
          } else if (u instanceof IdentityStmt) {
            IdentityStmt id = (IdentityStmt) u;
            if (id.getLeftOp().equals(returnBase)) returnBase = null;
          }
        }
      if (accessPath.isEmpty()) return Type.FALSE;
      /*
      // Find the corresponding access path in the setter
      for (Unit u : bodySetter.getUnits())
      	if (u instanceof AssignStmt) {
      		AssignStmt assign = (AssignStmt) u;
      		if (assign.getLeftOp() instanceof InstanceFieldRef
      				&& assign.getRightOp() instanceof Local) {
      			InstanceFieldRef iref = (InstanceFieldRef) assign.getLeftOp();
      			if (iref.getFieldRef().toString().equals(accessPath.get(accessPath.size() - 1).getFieldRef().toString())) {
      				// This is a starting point
      				boolean pathFound = false;
      				Local startLocal = (Local) iref.getBase();
      				int accessPathPos = accessPath.size() - 2;
      				while (startLocal != null) {
      					for (Unit u2 : bodySetter.getUnits()) {
      						if (u2 instanceof AssignStmt) {
      							AssignStmt assign2 = (AssignStmt) u2;
      							if (assign2.getLeftOp().equals(startLocal))
      								if (assign2.getRightOp() instanceof InstanceFieldRef) {
      									InstanceFieldRef ref = (InstanceFieldRef) assign2.getRightOp();
      									if (accessPath.get(accessPathPos--).getFieldRef().toString().equals(ref.getFieldRef().toString())) {
      										startLocal = (Local) ref.getBase();
      										break;
      									}
      									else
      										startLocal = null;
      								}
      								else
      									startLocal = null;
      						}
      						else if (u2 instanceof IdentityStmt) {
      							IdentityStmt id = (IdentityStmt) u2;
      							if (id.getLeftOp().equals(startLocal)) {
      								startLocal = null;
      								pathFound = true;
      								break;
      							}
      						}
      					}
      				}

      				if (pathFound) {
      					if (assign.getRightOp() instanceof Local) {
      						// Find the parameter being set
      						for (Unit u2 : bodySetter.getUnits())
      							if (u2 instanceof IdentityStmt) {
      								IdentityStmt id = (IdentityStmt) u2;
      								if (id.getLeftOp().equals(assign.getRightOp()))
      									return Type.TRUE;
      							}
      					}
      					break;
      				}
      			}
      		}
      	}
      return Type.FALSE;
      */
      return Type.TRUE;
    } catch (Exception ex) {
      System.err.println("Something went wrong:");
      ex.printStackTrace();
      return Type.NOT_SUPPORTED;
    }
  }