public static boolean addTryWithResourceJ11()

in src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java [218:345]


  public static boolean addTryWithResourceJ11(CatchStatement tryStatement, ControlFlowGraph graph, List<TryStatementJ11> stack) {
    // Doesn't have a catch block, probably already processed
    if (tryStatement.getStats().size() < 2) {
      return false;
    }

    if (!tryStatement.getVars().get(0).getVarType().getValue().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;
        }

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

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

          if (isCloseCall(first, inTry, graph)) {
            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);
          if (func == null) return false;
          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()) {
              Statement inTry = inner.getStats().get(0);

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

                // Check for closable invocation
                if (isCloseCall(first, inTry, graph)) {
                  closeable = (VarExprent) ((InvocationExprent)first).getInstance();
                  nullable = true;

                  // Double check that the variables in the null check and the closeable match
                  if (!closeable.getVarVersion().equals(((VarExprent)check).getVarVersion())) {
                    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.EdgeType.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, graph, nullable)) {
          return false;
        }
      }

      stack.add(new TryStatementJ11(destinations, closeable, nullable, assignment, edge, tryStatement));
      return true;
    }

    return false;
  }