diff --git a/FernFlower-Patches/0029-Improve-inferred-generic-types.patch b/FernFlower-Patches/0029-Improve-inferred-generic-types.patch index 431ab7d..9d05089 100644 --- a/FernFlower-Patches/0029-Improve-inferred-generic-types.patch +++ b/FernFlower-Patches/0029-Improve-inferred-generic-types.patch @@ -264,7 +264,7 @@ index 8f69e433dce5541e5f42693c67fbb9f8610821d2..1f27ed6c5ab25460b0e67c728c7fdcaa public void getBytecodeRange(BitSet values) { measureBytecode(values, lstOperands); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -index ebb845dff674965ff3e0e8011db33dae5270e24d..a02c40a8a8a2ad1a1888d8a5370625c29c858e27 100644 +index ebb845dff674965ff3e0e8011db33dae5270e24d..81a2b58f169819e4d320265dda487a4843f2c581 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -52,6 +52,7 @@ public class InvocationExprent extends Exprent { @@ -303,7 +303,7 @@ index ebb845dff674965ff3e0e8011db33dae5270e24d..a02c40a8a8a2ad1a1888d8a5370625c2 + StructClass mthCls = DecompilerContext.getStructContext().getClass(classname); + + if (desc != null && mthCls != null) { -+ boolean isNew = functype == TYP_INIT && mthCls.getSignature() != null; ++ boolean isNew = functype == TYP_INIT; + boolean isGenNew = isNew && mthCls.getSignature() != null; + if (desc.getSignature() != null || isGenNew) { + Map> named = getNamedGenerics(); @@ -463,7 +463,7 @@ index ebb845dff674965ff3e0e8011db33dae5270e24d..a02c40a8a8a2ad1a1888d8a5370625c2 + + int j = 0; + for (int i = start; i < lstParameters.size(); ++i) { -+ if (mask == null || mask.get(i) != null) { ++ if (mask == null || mask.get(i) == null) { + VarType paramType = desc.getSignature().parameterTypes.get(j++); + if (paramType.isGeneric()) { + diff --git a/FernFlower-Patches/0030-Improve-stack-var-processor-output.patch b/FernFlower-Patches/0030-Improve-stack-var-processor-output.patch index ea3b959..faf8ca9 100644 --- a/FernFlower-Patches/0030-Improve-stack-var-processor-output.patch +++ b/FernFlower-Patches/0030-Improve-stack-var-processor-output.patch @@ -320,7 +320,7 @@ index 1232e643fae990a7a3a9ee5f2e2ece46e607f934..1a085709ed7a120d109542e4bf710101 } \ No newline at end of file diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -index a02c40a8a8a2ad1a1888d8a5370625c29c858e27..44927da60f640d940d0ccb6c52d8e4eba42ed2aa 100644 +index 81a2b58f169819e4d320265dda487a4843f2c581..7b23c31e8989f86ad7245ef508d4e90762274367 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -166,6 +166,11 @@ public class InvocationExprent extends Exprent { diff --git a/FernFlower-Patches/0033-Add-explicit-cast-to-invocations-of-java-nio-Buffer-.patch b/FernFlower-Patches/0033-Add-explicit-cast-to-invocations-of-java-nio-Buffer-.patch index ba33e12..af31f04 100644 --- a/FernFlower-Patches/0033-Add-explicit-cast-to-invocations-of-java-nio-Buffer-.patch +++ b/FernFlower-Patches/0033-Add-explicit-cast-to-invocations-of-java-nio-Buffer-.patch @@ -7,7 +7,7 @@ Subject: [PATCH] Add explicit cast to invocations of java/nio/Buffer Java 9+ added overrides to these functions to return the specific subclass, however, when there is a compiler "bug" that when targeting release * or below, it will still reference these new methods, causing exceptions at runtime on Java 8. diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -index 44927da60f640d940d0ccb6c52d8e4eba42ed2aa..74e4440c8cb062db041ca853b7292196e89b106f 100644 +index 7b23c31e8989f86ad7245ef508d4e90762274367..a55e37e7ecc6d11c18d692434d935ecf436282ab 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -46,6 +46,8 @@ public class InvocationExprent extends Exprent { diff --git a/FernFlower-Patches/0041-More-correctly-handle-inner-class-synthetic-paramete.patch b/FernFlower-Patches/0041-More-correctly-handle-inner-class-synthetic-paramete.patch new file mode 100644 index 0000000..afb5e66 --- /dev/null +++ b/FernFlower-Patches/0041-More-correctly-handle-inner-class-synthetic-paramete.patch @@ -0,0 +1,155 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: zml +Date: Thu, 13 May 2021 23:55:33 -0700 +Subject: [PATCH] More correctly handle inner class synthetic parameters + + +diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +index fe372662be3fbd310f94831b47f21b92033a851c..f50e767ab81de739cad2059b5a8279fcd7cdba25 100644 +--- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java ++++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +@@ -35,6 +35,8 @@ import java.util.*; + import java.util.Map.Entry; + + public class NestedClassProcessor { ++ public static final String ENUM_SYNTHETIC_SUPER = ""; ++ + public void processClass(ClassNode root, ClassNode node) { + // hide synthetic lambda content methods + if (node.type == ClassNode.CLASS_LAMBDA && !node.lambdaInformation.is_method_reference) { +@@ -386,7 +388,6 @@ public class NestedClassProcessor { + for (ClassNode nd : node.nested) { + if (nd.type != ClassNode.CLASS_LAMBDA && + !nd.classStruct.isSynthetic() && +- (nd.access & CodeConstants.ACC_STATIC) == 0 && + (nd.access & CodeConstants.ACC_INTERFACE) == 0) { + clTypes |= nd.type; + +@@ -503,23 +504,12 @@ public class NestedClassProcessor { + + if (interPairMask == null) { // member or local and never instantiated + interPairMask = interMask != null ? new ArrayList<>(interMask) : new ArrayList<>(); +- +- boolean found = false; +- +- for (int i = 0; i < interPairMask.size(); i++) { +- if (interPairMask.get(i) != null) { +- if (found) { +- interPairMask.set(i, null); +- } +- found = true; +- } +- } ++ } else { ++ mergeListSignatures(interPairMask, interMask, true); + } + +- mergeListSignatures(interPairMask, interMask, true); +- + for (VarFieldPair pair : interPairMask) { +- if (pair != null && !pair.fieldKey.isEmpty()) { ++ if (pair != null && !pair.fieldKey.isEmpty() && !NestedClassProcessor.ENUM_SYNTHETIC_SUPER.equals(pair.fieldKey)) { + nestedNode.mapFieldsToVars.put(pair.fieldKey, pair.varPair); + } + } +@@ -764,7 +754,14 @@ public class NestedClassProcessor { + List fields = new ArrayList<>(md.params.length); + + int varIndex = 1; +- for (int i = 0; i < md.params.length; i++) { // no static methods allowed ++ int start = 0; ++ if ((wrapper.getClassStruct().getAccessFlags() & CodeConstants.ACC_ENUM) != 0) { // enums have 2x synthetic params. not handled by normal detection because they go to the superclass constructor rather than to synthetic fields ++ fields.add(new VarFieldPair(NestedClassProcessor.ENUM_SYNTHETIC_SUPER, new VarVersionPair(-1, 0))); ++ fields.add(new VarFieldPair(NestedClassProcessor.ENUM_SYNTHETIC_SUPER, new VarVersionPair(-1, 0))); ++ varIndex += 2; ++ start += 2; ++ } ++ for (int i = start; i < md.params.length; i++) { // no static methods allowed + String keyField = getEnclosingVarField(cl, method, graph, varIndex); + fields.add(keyField == null ? null : new VarFieldPair(keyField, new VarVersionPair(-1, 0))); // TODO: null? + varIndex += md.params[i].stackSize; +@@ -819,17 +816,31 @@ public class NestedClassProcessor { + return fd.getName().contains("$") && fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_PRIVATE); + } + ++ /** ++ * Merge two sets of method signatures. ++ * ++ * This ensures that synthetic parameters are properly captured when field writes may go through another constructor. ++ * ++ * @param first the list to modify ++ * @param second the list compared against ++ * @param both if the comparison list should also be modified to align ++ */ + private static void mergeListSignatures(List first, List second, boolean both) { +- int i = 1; ++ // Upstream this merges from the end of the list forwards ++ // However, synthetic parameters are added at the beginnings of method signatures (at least usually) ++ // so we really want to start from the beginning ++ // if it ends up that this assumption is not true, we'd have to do some sort of fuzzy matching here, or earlier ++ // on traverse multiple steps in the graph in getEnclosingVarField ++ int i = 0; + +- while (first.size() > i && second.size() > i) { +- VarFieldPair fObj = first.get(first.size() - i); +- VarFieldPair sObj = second.get(second.size() - i); ++ while (i < first.size() && i < second.size()) { ++ VarFieldPair fObj = first.get(i); ++ VarFieldPair sObj = second.get(i); + + if (!isEqual(both, fObj, sObj)) { +- first.set(first.size() - i, null); ++ first.set(i, null); + if (both) { +- second.set(second.size() - i, null); ++ second.set(i, null); + } + } + else if (fObj != null) { +@@ -844,44 +855,15 @@ public class NestedClassProcessor { + i++; + } + +- for (int j = 1; j <= first.size() - i; j++) { ++ for (int j = i; j < first.size(); j++) { + first.set(j, null); + } + + if (both) { +- for (int j = 1; j <= second.size() - i; j++) { ++ for (int j = i; j < second.size(); j++) { + second.set(j, null); + } + } +- +- // first +- if (first.isEmpty()) { +- if (!second.isEmpty() && both) { +- second.set(0, null); +- } +- } +- else if (second.isEmpty()) { +- first.set(0, null); +- } +- else { +- VarFieldPair fObj = first.get(0); +- VarFieldPair sObj = second.get(0); +- +- if (!isEqual(both, fObj, sObj)) { +- first.set(0, null); +- if (both) { +- second.set(0, null); +- } +- } +- else if (fObj != null) { +- if (fObj.varPair.var == -1) { +- fObj.varPair = sObj.varPair; +- } +- else { +- sObj.varPair = fObj.varPair; +- } +- } +- } + } + + private static boolean isEqual(boolean both, VarFieldPair fObj, VarFieldPair sObj) {