private VPPEntry mergeVars()

in src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java [518:616]


  private VPPEntry mergeVars(Statement stat, Map<Integer, VarVersion> parent, Map<Integer, VarVersion> leaked, Map<VarVersion, VarVersion> blacklist) {
    Map<Integer, VarVersion> this_vars = new HashMap<>();
    if (!parent.isEmpty())
      this_vars.putAll(parent);

    if (!stat.getVarDefinitions().isEmpty()) {
      for (int x = 0; x < stat.getVarDefinitions().size(); x++) {
        Exprent exp = stat.getVarDefinitions().get(x);
        if (exp.type == Exprent.EXPRENT_VAR) {
          VarExprent var = (VarExprent)exp;
          int index = varproc.getVarOriginalIndex(var.getIndex());
          if (this_vars.containsKey(index)) {
            stat.getVarDefinitions().remove(x);
            return new VPPEntry(var, this_vars.get(index));
          }
          this_vars.put(index, new VarVersion(var));
          leaked.put(index, new VarVersion(var));
        }
      }
    }

    Map<Integer, VarVersion> scoped = switch (stat.type) { // These are the type of statements that leak vars
      case BASIC_BLOCK, GENERAL, ROOT, SEQUENCE -> leaked;
      default -> null;
    };

    if (stat.getExprents() == null) {
      List<IMatchable> objs = stat.getSequentialObjects();
      for (int i = 0; i < objs.size(); i++) {
        Object obj = objs.get(i);
        if (obj instanceof Statement st) {

          //Map<VarVersionPair, VarVersionPair> blacklist_n = new HashMap<VarVersionPair, VarVersionPair>();
          Map<Integer, VarVersion> leaked_n = new HashMap<>();
          VPPEntry remap = mergeVars(st, this_vars, leaked_n, blacklist);

          if (remap != null) {
            return remap;
          }
          /* TODO: See if we can optimize and only go up till needed.
          while (remap != null) {
            System.out.println("Remapping: " + remap.getKey() + " -> " + remap.getValue());
            VarVersionPair var = parent.get(varproc.getRemapped(remap.getValue().var));
            if (remap.getValue().equals(var)) { //Drill up to original declaration.
              return remap;
            }
            if (!remapVar(stat, remap.getKey(), remap.getValue())) {
              blacklist_n.put(remap.getKey(), remap.getValue());
            }
            leaked_n.clear();
            remap = mergeVars(st, this_vars, leaked_n, blacklist_n);
          }
          */

          if (!leaked_n.isEmpty()) {
            if (stat.type == Statement.StatementType.IF) {
              IfStatement ifst = (IfStatement)stat;
              if (obj == ifst.getIfstat() || obj == ifst.getElsestat()) {
                leaked_n.clear(); // Force no leaking at the end of if blocks
                // We may need to do this for Switches as well.. But havent run into that issue yet...
              }
              else if (obj == ifst.getFirst()) {
                leaked.putAll(leaked_n); //First is outside the scope so leak!
              }
            } else if (stat.type == Statement.StatementType.SWITCH ||
                       stat.type == Statement.StatementType.SYNCHRONIZED) {
              if (obj == stat.getFirst()) {
                leaked.putAll(leaked_n); //First is outside the scope so leak!
              }
              else {
                leaked_n.clear();
              }
            }
            else if (stat.type == Statement.StatementType.TRY_CATCH ||
              stat.type == Statement.StatementType.CATCH_ALL) {
              leaked_n.clear(); // Catches can't leak anything!
            }
            this_vars.putAll(leaked_n);
          }
        }
        else if (obj instanceof Exprent exprent) {
          VPPEntry ret = processExprent(exprent, this_vars, scoped, blacklist);
          if (ret != null && isVarReadFirst(ret.getValue(), stat, i + 1)) {
            return ret;
          }
        }
      }
    }
    else {
      List<Exprent> exps = stat.getExprents();
      for (int i = 0; i < exps.size(); i++) {
        VPPEntry ret = processExprent(exps.get(i), this_vars, scoped, blacklist);
        if (ret != null && !isVarReadFirst(ret.getValue(), stat, i + 1)) {
          return ret;
        }
      }
    }
    return null; // We made it with no remaps!!!!!!!
  }