private Record getFinallyInformation()

in src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java [121:282]


  private Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) {
    Map<BasicBlock, Boolean> mapLast = new HashMap<>();

    BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead();
    BasicBlock firstBasicBlock = firstBlockStatement.getBlock();
    Instruction instrFirst = firstBasicBlock.getInstruction(0);

    int firstCode = switch (instrFirst.opcode) {
      case CodeConstants.opc_pop -> 1;
      case CodeConstants.opc_astore -> 2;
      default -> 0;
    };

    ExprProcessor proc = new ExprProcessor(methodDescriptor, varProcessor);
    proc.processStatement(root, cl);

    SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
    ssa.splitVariables(root, mt);

    List<Exprent> expressions = firstBlockStatement.getExprents();

    VarVersion pair = new VarVersion((VarExprent)((AssignmentExprent)expressions.get(firstCode == 2 ? 1 : 0)).getLeft());

    FlattenStatementsHelper flattenHelper = new FlattenStatementsHelper();
    DirectGraph dgraph = flattenHelper.buildDirectGraph(root);

    LinkedList<DirectNode> stack = new LinkedList<>();
    stack.add(dgraph.first);

    Set<DirectNode> setVisited = new HashSet<>();

    while (!stack.isEmpty()) {
      DirectNode node = stack.removeFirst();

      if (setVisited.contains(node)) {
        continue;
      }
      setVisited.add(node);

      BasicBlockStatement blockStatement = null;
      if (node.block != null) {
        blockStatement = node.block;
      }
      else if (node.predecessors.size() == 1) {
        blockStatement = node.predecessors.get(0).block;
      }

      boolean isTrueExit = true;

      if (firstCode != 1) {
        isTrueExit = false;

        for (int i = 0; i < node.exprents.size(); i++) {
          Exprent exprent = node.exprents.get(i);

          if (firstCode == 0) {
            List<Exprent> lst = exprent.getAllExprents();
            lst.add(exprent);

            boolean found = false;
            for (Exprent expr : lst) {
              if (expr.type == Exprent.EXPRENT_VAR && new VarVersion((VarExprent)expr).equals(pair)) {
                found = true;
                break;
              }
            }

            if (found) {
              found = false;
              if (exprent.type == Exprent.EXPRENT_EXIT) {
                ExitExprent exit = (ExitExprent)exprent;
                if (exit.getExitType() == ExitExprent.EXIT_THROW && exit.getValue().type == Exprent.EXPRENT_VAR) {
                  found = true;
                }
              }

              if (!found) {
                return null;
              }
              else {
                isTrueExit = true;
              }
            }
          }
          else {  // firstCode == 2
            // searching for a load instruction
            if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
              AssignmentExprent assignment = (AssignmentExprent)exprent;
              if (assignment.getRight().type == Exprent.EXPRENT_VAR &&
                  new VarVersion((VarExprent)assignment.getRight()).equals(pair)) {
                Exprent next = null;
                if (i == node.exprents.size() - 1) {
                  if (node.successors.size() == 1) {
                    DirectNode nd = node.successors.get(0);
                    if (!nd.exprents.isEmpty()) {
                      next = nd.exprents.get(0);
                    }
                  }
                }
                else {
                  next = node.exprents.get(i + 1);
                }

                boolean found = false;
                if (next != null && next.type == Exprent.EXPRENT_EXIT) {
                  ExitExprent exit = (ExitExprent)next;
                  if (exit.getExitType() == ExitExprent.EXIT_THROW && exit.getValue().type == Exprent.EXPRENT_VAR &&
                      assignment.getLeft().equals(exit.getValue())) {
                    found = true;
                  }
                }

                if (!found) {
                  return null;
                }
                else {
                  isTrueExit = true;
                }
              }
            }
          }
        }
      }

      // find finally exits
      if (blockStatement != null && blockStatement.getBlock() != null) {
        Statement handler = fstat.getHandler();
        for (StatEdge edge : blockStatement.getSuccessorEdges(EdgeType.DIRECT_ALL)) {
          if (edge.getType() != EdgeType.REGULAR && handler.containsStatement(blockStatement)
              && !handler.containsStatement(edge.getDestination())) {
            Boolean existingFlag = mapLast.get(blockStatement.getBlock());
            // note: the dummy node is also processed!
            if (existingFlag == null || !existingFlag) {
              mapLast.put(blockStatement.getBlock(), isTrueExit);
              break;
            }
          }
        }
      }

      stack.addAll(node.successors);
    }

    // an empty `finally` block?
    if (fstat.getHandler().type == StatementType.BASIC_BLOCK) {
      boolean isFirstLast = mapLast.containsKey(firstBasicBlock);
      InstructionSequence seq = firstBasicBlock.getSeq();

      boolean isEmpty = switch (firstCode) {
        case 0 -> isFirstLast && seq.length() == 1;
        case 1 -> seq.length() == 1;
        case 2 -> isFirstLast ? seq.length() == 3 : seq.length() == 1;
        default -> false;
      };

      if (isEmpty) {
        firstCode = 3;
      }
    }

    return new Record(firstCode, mapLast);
  }