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;
}