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