Collection<PsiStatement> (@NotNull ControlFlow flow, final int start, final int end, @NotNull IntList exitPoints, Class<? extends PsiStatement> @NotNull ... classesFilter) { if (end == start) { exitPoints.add(end); return Collections.emptyList(); } final Collection<PsiStatement> exitStatements = new HashSet<>(); InstructionClientVisitor<Void> visitor = new InstructionClientVisitor<Void>() { @Override public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { //[ven]This is a hack since Extract Method doesn't want to see throw's exit points processGotoStatement(exitStatements, findStatement(flow, offset), classesFilter); } @Override public void visitBranchingInstruction(BranchingInstruction instruction, int offset, int nextOffset) { processGoto(flow, start, end, exitPoints, exitStatements, instruction, findStatement(flow, offset), classesFilter); } // call/return do not incur exit points @Override public void visitReturnInstruction(ReturnInstruction instruction, int offset, int nextOffset) { } @Override public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { } @Override public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { visitInstruction(instruction, offset, nextOffset); } @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (offset >= end - 1) { int exitOffset = end; exitOffset = promoteThroughGotoChain(flow, exitOffset); if (!exitPoints.contains(exitOffset)) { exitPoints.add(exitOffset); } } } @Override public Void getResult() { return null; } }; depthFirstSearch(flow, visitor, start, end); return exitStatements; }