/** flow function for normal intraprocedural edges */
    public IUnaryFlowFunction getNormalFlowFunction(
        final BasicBlockInContext<IExplodedBasicBlock> src,
        BasicBlockInContext<IExplodedBasicBlock> dest) {
      final IExplodedBasicBlock ebb = src.getDelegate();
      SSAInstruction instruction = ebb.getInstruction();

      if (instruction instanceof SSAPutInstruction) {
        final SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
        if (putInstr.isStatic()) {
          return new IUnaryFlowFunction() {

            public IntSet getTargets(int d1) {
              // first, gen this statement
              int factNum =
                  domain.getMappedIndex(Pair.make(src.getNode(), ebb.getFirstInstructionIndex()));
              assert factNum != -1;
              MutableSparseIntSet result = MutableSparseIntSet.makeEmpty();
              result.add(factNum);
              // if incoming statement is some different statement that defs the same static field,
              // kill it; otherwise, keep it
              if (d1 != factNum) {
                IField staticField = cha.resolveField(putInstr.getDeclaredField());
                assert staticField != null;
                Pair<CGNode, Integer> otherPutInstrAndNode = domain.getMappedObject(d1);
                SSAPutInstruction otherPutInstr =
                    (SSAPutInstruction)
                        otherPutInstrAndNode.fst.getIR()
                            .getInstructions()[otherPutInstrAndNode.snd];
                IField otherStaticField = cha.resolveField(otherPutInstr.getDeclaredField());
                if (!staticField.equals(otherStaticField)) {
                  result.add(d1);
                }
              }
              return result;
            }

            public String toString() {
              return "Reaching Defs Normal Flow";
            }
          };
        }
      }
      // identity function when src block isn't for a putstatic
      return IdentityFlowFunction.identity();
    }
 /** flow function from caller to callee; just the identity function */
 public IUnaryFlowFunction getCallFlowFunction(
     BasicBlockInContext<IExplodedBasicBlock> src,
     BasicBlockInContext<IExplodedBasicBlock> dest,
     BasicBlockInContext<IExplodedBasicBlock> ret) {
   return IdentityFlowFunction.identity();
 }
 /**
  * the flow function for flow from a callee to caller where there was no flow from caller to
  * callee; just the identity function
  *
  * @see ReachingDefsProblem
  */
 public IFlowFunction getUnbalancedReturnFlowFunction(
     BasicBlockInContext<IExplodedBasicBlock> src,
     BasicBlockInContext<IExplodedBasicBlock> dest) {
   return IdentityFlowFunction.identity();
 }
 /**
  * flow function from call node to return node when there are no targets for the call site; not
  * a case we are expecting
  */
 public IUnaryFlowFunction getCallNoneToReturnFlowFunction(
     BasicBlockInContext<IExplodedBasicBlock> src,
     BasicBlockInContext<IExplodedBasicBlock> dest) {
   // if we're missing callees, just keep what information we have
   return IdentityFlowFunction.identity();
 }