public static boolean makeTryWithResourceJ11(CatchStatement tryStatement) {
    // Doesn't have a catch block, probably already processed
    if (tryStatement.getStats().size() < 2) {
      return false;
    }

    if (!tryStatement.getVars().get(0).getVarType().value.equals("java/lang/Throwable")) {
      return false;
    }

    Statement inner = tryStatement.getStats().get(1); // Get catch block

    VarExprent closeable = null;

    boolean nullable = false;

    if (inner instanceof SequenceStatement) {
      // Replace dummy inner with real inner
      inner = inner.getStats().get(0);

      // If the catch statement contains a simple try catch, then it's a nonnull resource
      if (inner instanceof CatchStatement) {
        if (inner.getStats().isEmpty()) {
          return false;
        }

        CatchStatement innerTry = (CatchStatement)inner;
        if (!innerTry.getVars().get(0).getVarType().value.equals("java/lang/Throwable")) {
          return false;
        }

        Statement inTry = inner.getStats().get(0);

        // Catch block contains a basic block inside which has the closeable invocation
        if (inTry instanceof BasicBlockStatement && !inTry.getExprents().isEmpty()) {
          Exprent first = inTry.getExprents().get(0);

          if (isCloseable(first)) {
            closeable = (VarExprent) ((InvocationExprent)first).getInstance();
          }
        }
      }

      // Nullable resource, contains null checks
      if (inner instanceof IfStatement) {
        Exprent ifCase = ((IfStatement)inner).getHeadexprent().getCondition();

        if (ifCase instanceof FunctionExprent) {
          // Will look like "if (!(!(var != null)))"
          FunctionExprent func = unwrapNegations((FunctionExprent) ifCase);

          Exprent check = func.getLstOperands().get(0);

          // If it's not a var, end processing early
          if (!(check instanceof VarExprent)) {
            return false;
          }

          // Make sure it's checking against null
          if (func.getLstOperands().get(1).getExprType().equals(VarType.VARTYPE_NULL)) {
            // Ensured that the if stat is a null check

            inner = ((IfStatement)inner).getIfstat();

            if (inner == null) {
              return false;
            }

            // Process try catch inside of if statement
            if (inner instanceof CatchStatement && !inner.getStats().isEmpty()) {
              if (inner.getStats().isEmpty()) {
                return false;
              }

              CatchStatement innerTry = (CatchStatement)inner;
              if (!innerTry.getVars().get(0).getVarType().value.equals("java/lang/Throwable")) {
                return false;
              }

              Statement inTry = inner.getStats().get(0);

              if (inTry instanceof BasicBlockStatement && !inTry.getExprents().isEmpty()) {
                Exprent first = inTry.getExprents().get(0);

                // Check for closable invocation
                if (isCloseable(first)) {
                  closeable = (VarExprent) ((InvocationExprent)first).getInstance();
                  nullable = true;

                  // Double check that the variables in the null check and the closeable match
                  if (!closeable.getVarVersionPair().equals(((VarExprent)check).getVarVersionPair())) {
                    closeable = null;
                  }
                }
              }
            }
          }
        }
      }
    }

    // Didn't find an autocloseable, return early
    if (closeable == null) {
      return false;
    }

    Set<Statement> destinations = findExitpoints(tryStatement);
    if (destinations.isEmpty()) {
      return false;
    }

    Statement check = tryStatement;
    List<StatEdge> preds = new ArrayList<>();
    while (check != null && preds.isEmpty()) {
      preds = check.getPredecessorEdges(StatEdge.TYPE_REGULAR);
      check = check.getParent();
    }

    if (preds.isEmpty()) {
      return false;
    }

    StatEdge edge = preds.get(0);
    if (edge.getSource() instanceof BasicBlockStatement) {
      AssignmentExprent assignment = findResourceDef(closeable, edge.getSource());

      if (assignment == null) {
        return false;
      }

      for (Statement destination : destinations) {
        if (!isValid(destination, closeable, nullable)) {
          return false;
        }
      }

      for (Statement destination : destinations) {
        removeClose(destination, nullable);
      }

      edge.getSource().getExprents().remove(assignment);

      // Add resource assignment to try
      tryStatement.getResources().add(0, assignment);

      // Get catch block
      Statement remove = tryStatement.getStats().get(1);

      // Flatten references to statement
      SequenceHelper.destroyAndFlattenStatement(remove);

      // Destroy catch block
      tryStatement.getStats().remove(1);

      return true;
    }

    return false;
  }
Processes try catch statements to turns them into try-with-resources statements wherever possible.
Including the entire classpath is generally needed for this to work as it needs to know which classes implement AutoCloseable.

@author ForgeFlower devs, SuperCoder79
src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java