void (VarTypeProcessor typeProcessor, DirectGraph graph, StructMethod mt) { Map<VarVersionPair, VarType> mapExprentMaxTypes = typeProcessor.getMaxExprentTypes(); Map<VarVersionPair, VarType> mapExprentMinTypes = typeProcessor.getMinExprentTypes(); Map<Integer, Set<Integer>> mapVarVersions = new HashMap<>(); for (VarVersionPair 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<VarVersionPair, 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++) { VarVersionPair firstPair = new VarVersionPair(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++) { VarVersionPair secondPair = new VarVersionPair(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); } }