class SConstantPropagatorAndFolder extends BodyTransformer {
  private static final Logger logger = LoggerFactory.getLogger(SConstantPropagatorAndFolder.class);

  public SConstantPropagatorAndFolder(Singletons.Global g) {
  }

  public static SConstantPropagatorAndFolder v() {
    return G.v().soot_shimple_toolkits_scalar_SConstantPropagatorAndFolder();
  }

  protected ShimpleBody sb;
  protected boolean debug;

  @Override
  protected void internalTransform(Body b, String phaseName, Map<String, String> options) {<FILL_FUNCTION_BODY>}

  /**
   * Propagates constants to the definition and uses of the relevant locals given a mapping. Notice that we use the Shimple
   * implementation of LocalDefs and LocalUses.
   **/
  protected void propagateResults(Map<Local, Constant> localToConstant) {
    ShimpleLocalDefs localDefs = new ShimpleLocalDefs(sb);
    ShimpleLocalUses localUses = new ShimpleLocalUses(sb);

    for (Local local : sb.getLocals()) {
      Constant constant = localToConstant.get(local);
      if (constant instanceof MetaConstant) {
        continue;
      }
      // update definition
      {
        DefinitionStmt stmt = (DefinitionStmt) localDefs.getDefsOf(local).get(0);

        ValueBox defSrcBox = stmt.getRightOpBox();
        Value defSrcOld = defSrcBox.getValue();

        if (defSrcBox.canContainValue(constant)) {
          defSrcBox.setValue(constant);

          // remove dangling pointers
          if (defSrcOld instanceof UnitBoxOwner) {
            ((UnitBoxOwner) defSrcOld).clearUnitBoxes();
          }
        } else if (debug) {
          logger.warn("Couldn't propagate constant " + constant + " to box " + defSrcBox.getValue() + " in unit " + stmt);
        }
      }
      // update uses
      for (UnitValueBoxPair pair : localUses.getUsesOf(local)) {
        ValueBox useBox = pair.getValueBox();

        if (useBox.canContainValue(constant)) {
          useBox.setValue(constant);
        } else if (debug) {
          logger.warn(
              "Couldn't propagate constant " + constant + " to box " + useBox.getValue() + " in unit " + pair.getUnit());
        }
      }
    }
  }

  /**
   * Removes the given list of fall through IfStmts from the body.
   **/
  protected void removeStmts(List<IfStmt> deadStmts) {
    Chain<Unit> units = sb.getUnits();
    for (IfStmt dead : deadStmts) {
      units.remove(dead);
      dead.clearUnitBoxes();
    }
  }

  /**
   * Replaces conditional branches by unconditional branches as given by the mapping.
   **/
  protected void replaceStmts(Map<Stmt, GotoStmt> stmtsToReplace) {
    Chain<Unit> units = sb.getUnits();
    for (Map.Entry<Stmt, GotoStmt> e : stmtsToReplace.entrySet()) {
      // important not to call clearUnitBoxes() on key since
      // replacement uses the same UnitBox
      units.swapWith(e.getKey(), e.getValue());
    }
  }
}

    if (!(b instanceof ShimpleBody)) {
      throw new RuntimeException("SConstantPropagatorAndFolder requires a ShimpleBody.");
    }
    ShimpleBody castBody = (ShimpleBody) b;
    if (!castBody.isSSA()) {
      throw new RuntimeException("ShimpleBody is not in proper SSA form as required by SConstantPropagatorAndFolder. "
          + "You may need to rebuild it or use ConstantPropagatorAndFolder instead.");
    }

    this.sb = castBody;
    this.debug = Options.v().debug() || castBody.getOptions().debug();

    if (Options.v().verbose()) {
      logger.debug("[" + castBody.getMethod().getName() + "] Propagating and folding constants (SSA)...");
    }

    // *** FIXME: What happens when Shimple is built with another UnitGraph?
    SCPFAnalysis scpf = new SCPFAnalysis(ExceptionalUnitGraphFactory.createExceptionalUnitGraph(castBody));
    propagateResults(scpf.getResults());
    if (PhaseOptions.getBoolean(options, "prune-cfg")) {
      removeStmts(scpf.getDeadStmts());
      replaceStmts(scpf.getStmtsToReplace());
    }
  
<methods>public non-sealed void <init>() ,public final void transform(soot.Body, java.lang.String, Map<java.lang.String,java.lang.String>) ,public final void transform(soot.Body, java.lang.String) ,public final void transform(soot.Body) <variables>private static final Map<java.lang.String,java.lang.String> enabledOnlyMap