class UselessAbruptStmtRemover extends DepthFirstAdapter {
  public static boolean DEBUG = false;

  ASTParentNodeFinder finder;
  ASTMethodNode methodNode;
  LabelToNodeMapper mapper;

  public UselessAbruptStmtRemover() {
    finder = null;
  }

  public UselessAbruptStmtRemover(boolean verbose) {
    super(verbose);
    finder = null;
  }

  public void inASTMethodNode(ASTMethodNode node) {
    methodNode = node;
    mapper = new LabelToNodeMapper();
    methodNode.apply(mapper);
  }

  public void caseASTStatementSequenceNode(ASTStatementSequenceNode node) {<FILL_FUNCTION_BODY>}

  public boolean checkChildLastInParent(ASTNode child, ASTNode parent) {
    List<Object> subBodies = parent.get_SubBodies();
    Iterator<Object> it = subBodies.iterator();

    while (it.hasNext()) {
      List subBody = null;
      if (parent instanceof ASTTryNode) {
        subBody = (List) ((ASTTryNode.container) it.next()).o;
      } else {
        subBody = (List) it.next();
      }

      if (subBody.contains(child)) {
        if (subBody.indexOf(child) != subBody.size() - 1) {
          return false;
        } else {
          return true;
        }
      }
    }

    return false;
  }
}

    Iterator<AugmentedStmt> it = node.getStatements().iterator();
    AugmentedStmt remove = null;
    ASTLabeledNode target = null;
    while (it.hasNext()) {
      AugmentedStmt as = it.next();
      Stmt s = as.get_Stmt();

      // we only care about break and continue stmts
      if (!(s instanceof DAbruptStmt)) {
        continue;
      }

      DAbruptStmt abrupt = (DAbruptStmt) s;
      String label = abrupt.getLabel().toString();
      if (label == null) {
        // could at some time implement a version of the same
        // analysis with implicit abrupt flow but not needed currently
        continue;
      }

      if (it.hasNext()) {
        // there is an abrupt stmt and this stmt seq node has something
        // afterwards...that is for sure dead code
        throw new DecompilationException("Dead code detected. Report to developer");
      }

      // get the target node
      Object temp = mapper.getTarget(label);
      if (temp == null) {
        continue;
        // throw new DecompilationException("Could not find target for abrupt stmt"+abrupt.toString());
      }

      target = (ASTLabeledNode) temp;

      // will need to find parents of ancestors see if we need to initialize the finder
      if (finder == null) {
        finder = new ASTParentNodeFinder();
        methodNode.apply(finder);
      }

      if (DEBUG) {
        System.out.println("Starting useless check for abrupt stmt: " + abrupt);
      }

      // start condition is that ancestor is the stmt seq node
      ASTNode ancestor = node;

      while (ancestor != target) {
        Object tempParent = finder.getParentOf(ancestor);
        if (tempParent == null) {
          throw new DecompilationException("Parent found was null!!. Report to Developer");
        }

        ASTNode ancestorsParent = (ASTNode) tempParent;
        if (DEBUG) {
          System.out.println("\tCurrent ancestorsParent has type" + ancestorsParent.getClass());
        }

        // ancestor should be last child of ancestorsParent
        if (!checkChildLastInParent(ancestor, ancestorsParent)) {
          if (DEBUG) {
            System.out.println("\t\tCurrent ancestorParent has more children after this ancestor");
          }

          // return from the method since this is the last stmt and we cant do anything
          return;
        }

        // ancestorsParent should not be a loop of any kind OR A SWITCH
        if (ancestorsParent instanceof ASTWhileNode || ancestorsParent instanceof ASTDoWhileNode
            || ancestorsParent instanceof ASTUnconditionalLoopNode || ancestorsParent instanceof ASTForLoopNode
            || ancestorsParent instanceof ASTSwitchNode) {
          if (DEBUG) {
            System.out.println("\t\tAncestorsParent is a loop shouldnt remove abrupt stmt");
          }
          return;
        }
        ancestor = ancestorsParent;
      }

      if (DEBUG) {
        System.out.println("\tGot to target without returning means we can remove stmt");
      }

      remove = as;
    } // end of while going through the statement sequence

    if (remove != null) {
      List<AugmentedStmt> stmts = node.getStatements();
      stmts.remove(remove);
      if (DEBUG) {
        System.out.println("\tRemoved abrupt stmt");
      }

      if (target != null) {
        if (DEBUG) {
          System.out.println("Invoking findAndKill on the target");
        }
        UselessLabelFinder.v().findAndKill(target);
      }
      // TODO what if we just emptied a stmt seq block??
      // not doing this for the moment

      // set modified flag make finder null
      G.v().ASTTransformations_modified = true;
      finder = null;
    }
  
<methods>public void <init>() ,public void <init>(boolean) ,public void caseASTAndCondition(soot.dava.internal.AST.ASTAndCondition) ,public void caseASTBinaryCondition(soot.dava.internal.AST.ASTBinaryCondition) ,public void caseASTDoWhileNode(soot.dava.internal.AST.ASTDoWhileNode) ,public void caseASTForLoopNode(soot.dava.internal.AST.ASTForLoopNode) ,public void caseASTIfElseNode(soot.dava.internal.AST.ASTIfElseNode) ,public void caseASTIfNode(soot.dava.internal.AST.ASTIfNode) ,public void caseASTLabeledBlockNode(soot.dava.internal.AST.ASTLabeledBlockNode) ,public void caseASTMethodNode(soot.dava.internal.AST.ASTMethodNode) ,public void caseASTOrCondition(soot.dava.internal.AST.ASTOrCondition) ,public void caseASTStatementSequenceNode(soot.dava.internal.AST.ASTStatementSequenceNode) ,public void caseASTSwitchNode(soot.dava.internal.AST.ASTSwitchNode) ,public void caseASTSynchronizedBlockNode(soot.dava.internal.AST.ASTSynchronizedBlockNode) ,public void caseASTTryNode(soot.dava.internal.AST.ASTTryNode) ,public void caseASTUnaryCondition(soot.dava.internal.AST.ASTUnaryCondition) ,public void caseASTUnconditionalLoopNode(soot.dava.internal.AST.ASTUnconditionalLoopNode) ,public void caseASTWhileNode(soot.dava.internal.AST.ASTWhileNode) ,public void caseArrayRef(soot.jimple.ArrayRef) ,public void caseBinopExpr(soot.jimple.BinopExpr) ,public void caseCastExpr(soot.jimple.CastExpr) ,public void caseDVariableDeclarationStmt(soot.dava.internal.javaRep.DVariableDeclarationStmt) ,public void caseDefinitionStmt(soot.jimple.DefinitionStmt) ,public void caseExpr(soot.jimple.Expr) ,public void caseExprOrRefValueBox(soot.ValueBox) ,public void caseInstanceFieldRef(soot.jimple.InstanceFieldRef) ,public void caseInstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) ,public void caseInstanceOfExpr(soot.jimple.InstanceOfExpr) ,public void caseInvokeExpr(soot.jimple.InvokeExpr) ,public void caseInvokeStmt(soot.jimple.InvokeStmt) ,public void caseNewArrayExpr(soot.jimple.NewArrayExpr) ,public void caseNewMultiArrayExpr(soot.jimple.NewMultiArrayExpr) ,public void caseRef(soot.jimple.Ref) ,public void caseReturnStmt(soot.jimple.ReturnStmt) ,public void caseStaticFieldRef(soot.jimple.StaticFieldRef) ,public void caseStmt(soot.jimple.Stmt) ,public void caseThrowStmt(soot.jimple.ThrowStmt) ,public void caseType(soot.Type) ,public void caseUnopExpr(soot.jimple.UnopExpr) ,public void caseValue(soot.Value) ,public void debug(java.lang.String, java.lang.String, java.lang.String) ,public void decideCaseExpr(soot.jimple.Expr) ,public void decideCaseExprOrRef(soot.Value) ,public void decideCaseRef(soot.jimple.Ref) ,public void inASTAndCondition(soot.dava.internal.AST.ASTAndCondition) ,public void inASTBinaryCondition(soot.dava.internal.AST.ASTBinaryCondition) ,public void inASTDoWhileNode(soot.dava.internal.AST.ASTDoWhileNode) ,public void inASTForLoopNode(soot.dava.internal.AST.ASTForLoopNode) ,public void inASTIfElseNode(soot.dava.internal.AST.ASTIfElseNode) ,public void inASTIfNode(soot.dava.internal.AST.ASTIfNode) ,public void inASTLabeledBlockNode(soot.dava.internal.AST.ASTLabeledBlockNode) ,public void inASTMethodNode(soot.dava.internal.AST.ASTMethodNode) ,public void inASTOrCondition(soot.dava.internal.AST.ASTOrCondition) ,public void inASTStatementSequenceNode(soot.dava.internal.AST.ASTStatementSequenceNode) ,public void inASTSwitchNode(soot.dava.internal.AST.ASTSwitchNode) ,public void inASTSynchronizedBlockNode(soot.dava.internal.AST.ASTSynchronizedBlockNode) ,public void inASTTryNode(soot.dava.internal.AST.ASTTryNode) ,public void inASTUnaryCondition(soot.dava.internal.AST.ASTUnaryCondition) ,public void inASTUnconditionalLoopNode(soot.dava.internal.AST.ASTUnconditionalLoopNode) ,public void inASTWhileNode(soot.dava.internal.AST.ASTWhileNode) ,public void inArrayRef(soot.jimple.ArrayRef) ,public void inBinopExpr(soot.jimple.BinopExpr) ,public void inCastExpr(soot.jimple.CastExpr) ,public void inDVariableDeclarationStmt(soot.dava.internal.javaRep.DVariableDeclarationStmt) ,public void inDefinitionStmt(soot.jimple.DefinitionStmt) ,public void inExpr(soot.jimple.Expr) ,public void inExprOrRefValueBox(soot.ValueBox) ,public void inInstanceFieldRef(soot.jimple.InstanceFieldRef) ,public void inInstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) ,public void inInstanceOfExpr(soot.jimple.InstanceOfExpr) ,public void inInvokeExpr(soot.jimple.InvokeExpr) ,public void inInvokeStmt(soot.jimple.InvokeStmt) ,public void inNewArrayExpr(soot.jimple.NewArrayExpr) ,public void inNewMultiArrayExpr(soot.jimple.NewMultiArrayExpr) ,public void inRef(soot.jimple.Ref) ,public void inReturnStmt(soot.jimple.ReturnStmt) ,public void inStaticFieldRef(soot.jimple.StaticFieldRef) ,public void inStmt(soot.jimple.Stmt) ,public void inThrowStmt(soot.jimple.ThrowStmt) ,public void inType(soot.Type) ,public void inUnopExpr(soot.jimple.UnopExpr) ,public void inValue(soot.Value) ,public void normalRetrieving(soot.dava.internal.AST.ASTNode) ,public void outASTAndCondition(soot.dava.internal.AST.ASTAndCondition) ,public void outASTBinaryCondition(soot.dava.internal.AST.ASTBinaryCondition) ,public void outASTDoWhileNode(soot.dava.internal.AST.ASTDoWhileNode) ,public void outASTForLoopNode(soot.dava.internal.AST.ASTForLoopNode) ,public void outASTIfElseNode(soot.dava.internal.AST.ASTIfElseNode) ,public void outASTIfNode(soot.dava.internal.AST.ASTIfNode) ,public void outASTLabeledBlockNode(soot.dava.internal.AST.ASTLabeledBlockNode) ,public void outASTMethodNode(soot.dava.internal.AST.ASTMethodNode) ,public void outASTOrCondition(soot.dava.internal.AST.ASTOrCondition) ,public void outASTStatementSequenceNode(soot.dava.internal.AST.ASTStatementSequenceNode) ,public void outASTSwitchNode(soot.dava.internal.AST.ASTSwitchNode) ,public void outASTSynchronizedBlockNode(soot.dava.internal.AST.ASTSynchronizedBlockNode) ,public void outASTTryNode(soot.dava.internal.AST.ASTTryNode) ,public void outASTUnaryCondition(soot.dava.internal.AST.ASTUnaryCondition) ,public void outASTUnconditionalLoopNode(soot.dava.internal.AST.ASTUnconditionalLoopNode) ,public void outASTWhileNode(soot.dava.internal.AST.ASTWhileNode) ,public void outArrayRef(soot.jimple.ArrayRef) ,public void outBinopExpr(soot.jimple.BinopExpr) ,public void outCastExpr(soot.jimple.CastExpr) ,public void outDVariableDeclarationStmt(soot.dava.internal.javaRep.DVariableDeclarationStmt) ,public void outDefinitionStmt(soot.jimple.DefinitionStmt) ,public void outExpr(soot.jimple.Expr) ,public void outExprOrRefValueBox(soot.ValueBox) ,public void outInstanceFieldRef(soot.jimple.InstanceFieldRef) ,public void outInstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) ,public void outInstanceOfExpr(soot.jimple.InstanceOfExpr) ,public void outInvokeExpr(soot.jimple.InvokeExpr) ,public void outInvokeStmt(soot.jimple.InvokeStmt) ,public void outNewArrayExpr(soot.jimple.NewArrayExpr) ,public void outNewMultiArrayExpr(soot.jimple.NewMultiArrayExpr) ,public void outRef(soot.jimple.Ref) ,public void outReturnStmt(soot.jimple.ReturnStmt) ,public void outStaticFieldRef(soot.jimple.StaticFieldRef) ,public void outStmt(soot.jimple.Stmt) ,public void outThrowStmt(soot.jimple.ThrowStmt) ,public void outType(soot.Type) ,public void outUnopExpr(soot.jimple.UnopExpr) ,public void outValue(soot.Value) <variables>public boolean DEBUG,boolean verbose