in src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java [140:238]
private static void simpleMerge(VarTypeProcessor typeProcessor, DirectGraph graph, StructMethod mt) {
Map<VarVersion, VarType> mapExprentMaxTypes = typeProcessor.getMaxExprentTypes();
Map<VarVersion, VarType> mapExprentMinTypes = typeProcessor.getMinExprentTypes();
Map<Integer, Set<Integer>> mapVarVersions = new HashMap<>();
for (VarVersion pair : mapExprentMinTypes.keySet()) {
if (pair.version >= 0) { // don't merge constants
mapVarVersions.computeIfAbsent(pair.var, k -> new HashSet<>()).add(pair.version);
}
}
boolean is_method_static = mt.hasModifier(CodeConstants.ACC_STATIC);
Map<VarVersion, Integer> mapMergedVersions = new HashMap<>();
for (Entry<Integer, Set<Integer>> ent : mapVarVersions.entrySet()) {
if (ent.getValue().size() > 1) {
List<Integer> lstVersions = new ArrayList<>(ent.getValue());
Collections.sort(lstVersions);
for (int i = 0; i < lstVersions.size(); i++) {
VarVersion firstPair = new VarVersion(ent.getKey(), lstVersions.get(i));
VarType firstType = mapExprentMinTypes.get(firstPair);
if (firstPair.var == 0 && firstPair.version == 1 && !is_method_static) {
continue; // don't merge 'this' variable
}
for (int j = i + 1; j < lstVersions.size(); j++) {
VarVersion secondPair = new VarVersion(ent.getKey(), lstVersions.get(j));
VarType secondType = mapExprentMinTypes.get(secondPair);
if (firstType.equals(secondType) ||
firstType.equals(VarType.VARTYPE_NULL) && secondType.getType() == CodeConstants.TYPE_OBJECT ||
secondType.equals(VarType.VARTYPE_NULL) && firstType.getType() == CodeConstants.TYPE_OBJECT ||
firstType.getTypeFamily() == CodeConstants.TYPE_FAMILY_INTEGER && secondType.getTypeFamily() == CodeConstants.TYPE_FAMILY_INTEGER) {
VarType firstMaxType = mapExprentMaxTypes.get(firstPair);
VarType secondMaxType = mapExprentMaxTypes.get(secondPair);
VarType type = firstMaxType == null ? secondMaxType :
secondMaxType == null ? firstMaxType :
VarType.getCommonMinType(firstMaxType, secondMaxType);
if (firstType.getTypeFamily() == CodeConstants.TYPE_FAMILY_INTEGER && secondType.getTypeFamily() == CodeConstants.TYPE_FAMILY_INTEGER) {
type = switch (secondType.getType()) {
case CodeConstants.TYPE_INT -> VarType.VARTYPE_INT;
case CodeConstants.TYPE_SHORT -> firstType.getType() == CodeConstants.TYPE_INT ? null : VarType.VARTYPE_SHORT;
case CodeConstants.TYPE_CHAR -> switch (firstType.getType()) {
case CodeConstants.TYPE_INT, CodeConstants.TYPE_SHORT -> null;
default -> VarType.VARTYPE_CHAR;
};
case CodeConstants.TYPE_SHORTCHAR -> switch (firstType.getType()) {
case CodeConstants.TYPE_INT, CodeConstants.TYPE_SHORT, CodeConstants.TYPE_CHAR -> null;
default -> VarType.VARTYPE_SHORTCHAR;
};
case CodeConstants.TYPE_BYTECHAR -> switch (firstType.getType()) {
case CodeConstants.TYPE_INT, CodeConstants.TYPE_SHORT, CodeConstants.TYPE_CHAR, CodeConstants.TYPE_SHORTCHAR -> null;
default -> VarType.VARTYPE_BYTECHAR;
};
case CodeConstants.TYPE_BYTE -> switch (firstType.getType()) {
case CodeConstants.TYPE_INT, CodeConstants.TYPE_SHORT, CodeConstants.TYPE_CHAR, CodeConstants.TYPE_SHORTCHAR, CodeConstants.TYPE_BYTECHAR ->
null;
default -> VarType.VARTYPE_BYTE;
};
default -> type;
};
if (type == null) {
continue;
}
firstType = type;
mapExprentMinTypes.put(firstPair, type);
}
mapExprentMaxTypes.put(firstPair, type);
mapMergedVersions.put(secondPair, firstPair.version);
mapExprentMaxTypes.remove(secondPair);
mapExprentMinTypes.remove(secondPair);
if (firstType.equals(VarType.VARTYPE_NULL)) {
mapExprentMinTypes.put(firstPair, secondType);
firstType = secondType;
}
typeProcessor.getFinalVariables().put(firstPair, VarProcessor.VAR_NON_FINAL);
lstVersions.remove(j);
//noinspection AssignmentToForLoopParameter
j--;
}
}
}
}
}
if (!mapMergedVersions.isEmpty()) {
updateVersions(graph, mapMergedVersions);
}
}