From 7534b3cac6bb8b93a03e3b39533e0bab38de9a61 Mon Sep 17 00:00:00 2001 From: SizableShrimp Date: Tue, 21 Mar 2023 22:41:17 -0500 Subject: [PATCH 01/22] Rebase on upstream 4961b5b (#138) --- FernFlower | 2 +- ...izers-for-anon-and-synthetic-classes.patch | 4 +- ...screpancies-to-produce-stable-output.patch | 6 +- ...Convert-Exprent.bytecode-to-a-BitMap.patch | 56 +++++++++---------- ...e-DotExporter-for-debugging-purposes.patch | 2 +- ...pport-for-Enhanced-For-loop-detectio.patch | 24 ++++---- ...of-Generics-system-for-better-output.patch | 55 +++++++++--------- .../0010-Improvements-to-var-and-var.patch | 8 +-- .../0011-JAD-Style-variable-naming.patch | 19 ++----- .../0012-Fix-primitive-un-boxing-issues.patch | 6 +- ...ance-Generic-Invocations-Temporarily.patch | 6 +- ...Class-Objects.requireNonNull-cleanup.patch | 4 +- ...output-for-float-and-double-literals.patch | 2 +- .../0024-Add-try-with-resource-support.patch | 4 +- ...and-enclosing-class-when-encounterin.patch | 2 +- .../0026-Fix-ambiguous-lambdas.patch | 6 +- .../0027-Fix-field-initalizers.patch | 4 +- .../0028-Improve-inferred-generic-types.patch | 26 ++++----- ...9-Improve-stack-var-processor-output.patch | 12 ++-- ...t-to-invocations-of-java-nio-Buffer-.patch | 2 +- ...change-to-FieldExprent-getExprentUse.patch | 2 +- ...t-It-will-filter-what-classes-are-de.patch | 2 +- ...ot-rebuild-variable-names-in-lambdas.patch | 2 +- ...037-Add-toString-to-MethodDescriptor.patch | 2 +- .../0038-Make-decomp-threaded.patch | 2 +- .../0040-Fixup-J9-string-concat.patch | 7 +-- ...when-finding-where-to-inject-local-c.patch | 6 +- ...Reduce-allocations-in-getAllExprents.patch | 28 +++++----- 28 files changed, 145 insertions(+), 156 deletions(-) diff --git a/FernFlower b/FernFlower index 0e3593f..4961b5b 160000 --- a/FernFlower +++ b/FernFlower @@ -1 +1 @@ -Subproject commit 0e3593f12741eed59e88368eba933bb10fd4f6a6 +Subproject commit 4961b5bb7f9e06c4dd15e5e3def5a25773e895a1 diff --git a/FernFlower-Patches/0003-Fix-initializers-for-anon-and-synthetic-classes.patch b/FernFlower-Patches/0003-Fix-initializers-for-anon-and-synthetic-classes.patch index d86e8a7..29e15fd 100644 --- a/FernFlower-Patches/0003-Fix-initializers-for-anon-and-synthetic-classes.patch +++ b/FernFlower-Patches/0003-Fix-initializers-for-anon-and-synthetic-classes.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Fix initializers for anon and synthetic classes diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java -index c012edd94f3f13c3bde885c992a74ce6d58eb0ee..1989a01b158570651f332cf80dca0e0baeb4153c 100644 +index 31f14c60939faaf73e8b971cb64c81b49decda81..9b4e9fb3ab0a2f54c124c8a4c3943e6d7a5d01d2 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -46,6 +46,7 @@ public class ClassWriter { @@ -17,7 +17,7 @@ index c012edd94f3f13c3bde885c992a74ce6d58eb0ee..1989a01b158570651f332cf80dca0e0b if (node.type == ClassNode.CLASS_ROOT && !cl.isVersion5() && diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index 168d7dfdeb65138ef7c26e30971738cd5161ffff..4a539357120d333d47f20f5e05b57ef4ad7b1fa8 100644 +index b09304aac7771bda2dcec3ef535f9035904f3c94..8dc45a1de093a5e81ef74e034faf2041618ced99 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -88,6 +88,31 @@ public class ClassesProcessor implements CodeConstants { diff --git a/FernFlower-Patches/0004-Fix-output-discrepancies-to-produce-stable-output.patch b/FernFlower-Patches/0004-Fix-output-discrepancies-to-produce-stable-output.patch index 6eb7cc6..73c6a48 100644 --- a/FernFlower-Patches/0004-Fix-output-discrepancies-to-produce-stable-output.patch +++ b/FernFlower-Patches/0004-Fix-output-discrepancies-to-produce-stable-output.patch @@ -7,7 +7,7 @@ Running JVM and timestamp result in output varying between environments and runs. diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index 4a539357120d333d47f20f5e05b57ef4ad7b1fa8..9104ad3f1edae3deb11913bb08d101269370ca7d 100644 +index 8dc45a1de093a5e81ef74e034faf2041618ced99..8173ecd04da97e5e9a8f5f9a2e309726439697e0 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -249,6 +249,7 @@ public class ClassesProcessor implements CodeConstants { @@ -156,7 +156,7 @@ index 05e6e2d720aa5812ef12c4741eab06b8ea477e0f..f9c8c6a0334512699c545c8812071947 } } diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 7fca17c41c49b5378614130cf3b94b4aef6d1176..09eb2ca3b49093d291aaa4fc8bb769316d5a62ac 100644 +index da1fc15420faf03e1afbf74c39f888a6cb9c9ce8..6e5fe5474d6878d789758a5e7791b03e5da6685e 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -218,6 +218,7 @@ public class NestedClassProcessor { @@ -354,7 +354,7 @@ index 82ae0a25a20d2727f611d359e699d6666d1e0ae4..a86f0d2887c6c19cb1d911ec43830eb6 return res; diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index caa160fdc4ff5954b0976b11d81177278ae79ab6..39df4ddd7afa01bba116063323630e514679a01f 100644 +index 743074d1b43f6b331cef74c94bb11a49fefbfb61..623d59228cc526cca3bbd52e95e4d493c689f133 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java @@ -216,7 +216,7 @@ public class ConstExprent extends Exprent { diff --git a/FernFlower-Patches/0005-Convert-Exprent.bytecode-to-a-BitMap.patch b/FernFlower-Patches/0005-Convert-Exprent.bytecode-to-a-BitMap.patch index fb8047f..2b12c8a 100644 --- a/FernFlower-Patches/0005-Convert-Exprent.bytecode-to-a-BitMap.patch +++ b/FernFlower-Patches/0005-Convert-Exprent.bytecode-to-a-BitMap.patch @@ -141,7 +141,7 @@ index c6a23b3277c3a93be621d6686b1554d51be01c9b..32ca965883f26cd8944bfb5e838d5cf5 } } diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 09eb2ca3b49093d291aaa4fc8bb769316d5a62ac..8126a50cf043593c0a041ea8942971f12cf4f090 100644 +index 6e5fe5474d6878d789758a5e7791b03e5da6685e..327a6e64f06d7ef60dc1bb3139aab490a2f7c2df 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -533,7 +533,7 @@ public class NestedClassProcessor { @@ -163,7 +163,7 @@ index 09eb2ca3b49093d291aaa4fc8bb769316d5a62ac..8126a50cf043593c0a041ea8942971f1 } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java -index c78b5ea78197f3c18ffb99caf5bd0e6bb49469f2..d85dead7cab48a9f551cb1226ef952807a067ec8 100644 +index f4cb77bea6031ddfe1197fb9d684f95ef39cda5a..5d47c847133cf0413365eddd5f1a2104b2f6ac6b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java @@ -11,8 +11,8 @@ import org.jetbrains.java.decompiler.struct.gen.VarType; @@ -380,7 +380,7 @@ index ae166cc9ea414d5a0b698d8d06c7a24836c21316..478a3aef4cbc9d555abd82e38200a62b BasicBlock dummyBlock = new BasicBlock(++graph.last_id, seq); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java -index 84de9258ddf94a35d4b1b1854e6a9bb4755214c5..982b660190ba9488c3ff62022aca0dfecbefab48 100644 +index 05849823262a46b66561164a0f0257123ce5307a..4beaf1ee874de373d956177ece541f0ecce64dc4 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java @@ -6,6 +6,7 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; @@ -391,7 +391,7 @@ index 84de9258ddf94a35d4b1b1854e6a9bb4755214c5..982b660190ba9488c3ff62022aca0dfe import java.util.List; import java.util.Objects; -@@ -98,4 +99,10 @@ public class AnnotationExprent extends Exprent { +@@ -97,4 +98,10 @@ public class AnnotationExprent extends Exprent { parNames.equals(ann.parNames) && parValues.equals(ann.parValues); } @@ -404,7 +404,7 @@ index 84de9258ddf94a35d4b1b1854e6a9bb4755214c5..982b660190ba9488c3ff62022aca0dfe } \ No newline at end of file diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java -index c5bce7deb9b3ddee4adb41e356838979c2508fac..88b429ca3bc60303f9075eab36e279f9c58f4520 100644 +index e2b79d56e9f7c2ca22713e83dbd2aeddce5f9885..406848324e427a2b18d3666e321172f0f130ec4c 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java @@ -14,7 +14,7 @@ public class ArrayExprent extends Exprent { @@ -416,7 +416,7 @@ index c5bce7deb9b3ddee4adb41e356838979c2508fac..88b429ca3bc60303f9075eab36e279f9 super(EXPRENT_ARRAY); this.array = array; this.index = index; -@@ -106,4 +106,11 @@ public class ArrayExprent extends Exprent { +@@ -105,4 +105,11 @@ public class ArrayExprent extends Exprent { public Exprent getIndex() { return index; } @@ -453,7 +453,7 @@ index 0dcb63d34c036a9cd21e21d77c2ea01f6f5b9266..097c10a32ed819368c48efa51866420c + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -index 13faa7fd16307e584d00bdf9f990e7cc7245babd..6cc60fd5314369cef21bd56c12e2af8e4c56292d 100644 +index b8678cdc0f0e778c3d1c8834ae764bbaa2e77ae1..06567749310f70d0f3263a9b2bad4588237bdda9 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java @@ -36,7 +36,7 @@ public class AssignmentExprent extends Exprent { @@ -465,7 +465,7 @@ index 13faa7fd16307e584d00bdf9f990e7cc7245babd..6cc60fd5314369cef21bd56c12e2af8e super(EXPRENT_ASSIGNMENT); this.left = left; this.right = right; -@@ -166,6 +166,13 @@ public class AssignmentExprent extends Exprent { +@@ -165,6 +165,13 @@ public class AssignmentExprent extends Exprent { condType == as.getCondType(); } @@ -480,7 +480,7 @@ index 13faa7fd16307e584d00bdf9f990e7cc7245babd..6cc60fd5314369cef21bd56c12e2af8e // getter and setter methods // ***************************************************************************** diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index 39df4ddd7afa01bba116063323630e514679a01f..56745ac71bbff7cbf8353579cd09f7482206677f 100644 +index 623d59228cc526cca3bbd52e95e4d493c689f133..b0bda600031b4cc52b6b083d5afd07a92ccef1af 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java @@ -52,20 +52,20 @@ public class ConstExprent extends Exprent { @@ -508,7 +508,7 @@ index 39df4ddd7afa01bba116063323630e514679a01f..56745ac71bbff7cbf8353579cd09f748 super(EXPRENT_CONST); this.constType = constType; this.value = value; -@@ -497,6 +497,11 @@ public class ConstExprent extends Exprent { +@@ -496,6 +496,11 @@ public class ConstExprent extends Exprent { return boolPermitted; } @@ -521,7 +521,7 @@ index 39df4ddd7afa01bba116063323630e514679a01f..56745ac71bbff7cbf8353579cd09f748 // IMatchable implementation // ***************************************************************************** diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -index 8dfa6cb4ad9ff9e465a1b42ca206e55ac07aabf8..b0c626320205e7e6fac1f8ceafdffbe89a5daf41 100644 +index 655e56241cf1d4eaa8bad524851f682c7af2bfb9..54f6a306cd28f68879d25a536a1dea7a496a4aa3 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java @@ -16,9 +16,9 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode; @@ -544,7 +544,7 @@ index 8dfa6cb4ad9ff9e465a1b42ca206e55ac07aabf8..b0c626320205e7e6fac1f8ceafdffbe8 super(EXPRENT_EXIT); this.exitType = exitType; this.value = value; -@@ -141,6 +141,13 @@ public class ExitExprent extends Exprent { +@@ -140,6 +140,13 @@ public class ExitExprent extends Exprent { return retType; } @@ -628,7 +628,7 @@ index 9b1b3de632a63bbba1f5f7a99d5f75bf537bd171..67fc1f2beab815f0ca07ecf8a34b98fa } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -index ec3a8668a94c7da89091a09a3002fd14346cc684..11669fe44ea78ab7322b82c844c8b220ca1a9975 100644 +index 4cd97c42682b27f96414ddf5302fc81db2561e56..379242393a83c6b3502a88c8d745a5b0bc1b5476 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -19,9 +19,9 @@ import org.jetbrains.java.decompiler.util.TextBuffer; @@ -656,7 +656,7 @@ index ec3a8668a94c7da89091a09a3002fd14346cc684..11669fe44ea78ab7322b82c844c8b220 super(EXPRENT_FIELD); this.name = name; this.classname = classname; -@@ -183,6 +183,12 @@ public class FieldExprent extends Exprent { +@@ -182,6 +182,12 @@ public class FieldExprent extends Exprent { return name; } @@ -670,7 +670,7 @@ index ec3a8668a94c7da89091a09a3002fd14346cc684..11669fe44ea78ab7322b82c844c8b220 // IMatchable implementation // ***************************************************************************** diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index a4ee85ba5deafed6f9618f9a8b93c5f554878a1d..ac2b3a50e65c46ff998173335d505cdfc8a27b21 100644 +index 4290039f07249ef112eb357ba0c9914ef5c08b40..b2b26fb3f8b075182caee14d57b4cc351ffb120a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -183,7 +183,7 @@ public class FunctionExprent extends Exprent { @@ -700,7 +700,7 @@ index a4ee85ba5deafed6f9618f9a8b93c5f554878a1d..ac2b3a50e65c46ff998173335d505cdf this(funcType, new ArrayList<>(1), bytecodeOffsets); lstOperands.add(operand); } -@@ -566,6 +566,12 @@ public class FunctionExprent extends Exprent { +@@ -565,6 +565,12 @@ public class FunctionExprent extends Exprent { this.implicitType = implicitType; } @@ -714,7 +714,7 @@ index a4ee85ba5deafed6f9618f9a8b93c5f554878a1d..ac2b3a50e65c46ff998173335d505cdf // IMatchable implementation // ***************************************************************************** diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java -index d5a743fd1a4e068616a82e8f23d119a8ba2b1d59..18d2c40d9af0e822004f4baaa3c6b567914a7545 100644 +index fda309fdc9d9fcaba4d089778122a56d1524e083..7c9ee0a57cd291ae20b466d70f57a8f11bf4abaa 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java @@ -9,9 +9,9 @@ import org.jetbrains.java.decompiler.util.ListStack; @@ -746,7 +746,7 @@ index d5a743fd1a4e068616a82e8f23d119a8ba2b1d59..18d2c40d9af0e822004f4baaa3c6b567 super(EXPRENT_IF); this.condition = condition; -@@ -135,4 +135,10 @@ public class IfExprent extends Exprent { +@@ -134,4 +134,10 @@ public class IfExprent extends Exprent { public void setCondition(Exprent condition) { this.condition = condition; } @@ -760,7 +760,7 @@ index d5a743fd1a4e068616a82e8f23d119a8ba2b1d59..18d2c40d9af0e822004f4baaa3c6b567 + } +} 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 d4ce3d808e9802b9f25a0a07a821f18fe3fed3f4..d94561755621c6517976a763f8b9a0a4e49528e2 100644 +index dc9c2a593185c2f5de7289b0c7676071bf50f5a4..3cedf46af2faa91029231205455a1df1db7be3de 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -65,7 +65,7 @@ public class InvocationExprent extends Exprent { @@ -772,7 +772,7 @@ index d4ce3d808e9802b9f25a0a07a821f18fe3fed3f4..d94561755621c6517976a763f8b9a0a4 this(); name = cn.elementname; -@@ -603,6 +603,13 @@ public class InvocationExprent extends Exprent { +@@ -602,6 +602,13 @@ public class InvocationExprent extends Exprent { return bootstrapArguments; } @@ -787,7 +787,7 @@ index d4ce3d808e9802b9f25a0a07a821f18fe3fed3f4..d94561755621c6517976a763f8b9a0a4 // IMatchable implementation // ***************************************************************************** diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java -index 5c4b2f37b57ec1f084e4147f2d9605e89d895b91..3ad223c61453159d096405bb73184644595b75a9 100644 +index 7259ce4ee91540cabf7a76105a5f18b2ab0390fa..cd465813bc3e9076d3bbafd1c7b10c9bed0a1407 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java @@ -7,9 +7,9 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; @@ -810,7 +810,7 @@ index 5c4b2f37b57ec1f084e4147f2d9605e89d895b91..3ad223c61453159d096405bb73184644 super(EXPRENT_MONITOR); this.monType = monType; this.value = value; -@@ -75,4 +75,10 @@ public class MonitorExprent extends Exprent { +@@ -74,4 +74,10 @@ public class MonitorExprent extends Exprent { public Exprent getValue() { return value; } @@ -822,7 +822,7 @@ index 5c4b2f37b57ec1f084e4147f2d9605e89d895b91..3ad223c61453159d096405bb73184644 + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -index 6257de67e8acd4b4882c758befa3c1e5223ddc0c..6df45768b067fd2e01ffd61bb157158cb369ad7e 100644 +index 2f8da49a36ee84e09ff6192aea5d0904c4f06255..c47ae33d7d62a5049a89bb586032fc18bdc80173 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -31,11 +31,11 @@ public class NewExprent extends Exprent { @@ -839,7 +839,7 @@ index 6257de67e8acd4b4882c758befa3c1e5223ddc0c..6df45768b067fd2e01ffd61bb157158c super(EXPRENT_NEW); this.newType = newType; this.lstDims = lstDims; -@@ -436,6 +436,14 @@ public class NewExprent extends Exprent { +@@ -435,6 +435,14 @@ public class NewExprent extends Exprent { Objects.equals(lstArrayElements, ne.lstArrayElements); } @@ -855,7 +855,7 @@ index 6257de67e8acd4b4882c758befa3c1e5223ddc0c..6df45768b067fd2e01ffd61bb157158c return constructor; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java -index 3b77fa20c3bfe1790e5f9386b5a38f02ca9c51fe..105c4d951f806fffb8d42386933a7629fa61d76c 100644 +index f475db7b7441d47661340b366116dbae7b1d9e5e..11000d30cbdc93e360cb1bc96b53987bc692e3bd 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -9,16 +9,16 @@ import org.jetbrains.java.decompiler.struct.gen.VarType; @@ -877,7 +877,7 @@ index 3b77fa20c3bfe1790e5f9386b5a38f02ca9c51fe..105c4d951f806fffb8d42386933a7629 super(EXPRENT_SWITCH); this.value = value; -@@ -100,6 +100,22 @@ public class SwitchExprent extends Exprent { +@@ -99,6 +99,22 @@ public class SwitchExprent extends Exprent { return Objects.equals(value, sw.getValue()); } @@ -901,7 +901,7 @@ index 3b77fa20c3bfe1790e5f9386b5a38f02ca9c51fe..105c4d951f806fffb8d42386933a7629 return value; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index eb0ef2bf829f55541711e24e483b68890735320a..4c40e5152ffca092883170401453525093da011a 100644 +index e488a34ea11ab46cd1bd6383cd332f05d45df2af..2b508a172340285dff5afa73cd4d7fcbf0dfeaff 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -26,6 +26,7 @@ import org.jetbrains.java.decompiler.util.TextUtil; @@ -963,7 +963,7 @@ index eb0ef2bf829f55541711e24e483b68890735320a..4c40e5152ffca0928831704014535250 if (originalIndex != null) { // first try from signature if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -@@ -181,6 +182,11 @@ public class VarExprent extends Exprent { +@@ -180,6 +181,11 @@ public class VarExprent extends Exprent { Objects.equals(getVarType(), ve.getVarType()); // FIXME: varType comparison redundant? } diff --git a/FernFlower-Patches/0007-Reintroduce-DotExporter-for-debugging-purposes.patch b/FernFlower-Patches/0007-Reintroduce-DotExporter-for-debugging-purposes.patch index a6b010b..0d3d6de 100644 --- a/FernFlower-Patches/0007-Reintroduce-DotExporter-for-debugging-purposes.patch +++ b/FernFlower-Patches/0007-Reintroduce-DotExporter-for-debugging-purposes.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Reintroduce DotExporter for debugging purposes diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 8126a50cf043593c0a041ea8942971f12cf4f090..216db28b337c729ea839415bdccc3b48a1219709 100644 +index 327a6e64f06d7ef60dc1bb3139aab490a2f7c2df..7d41769adee0974a02e0ef5a0518f9f9e53c8b58 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -24,6 +24,7 @@ import org.jetbrains.java.decompiler.struct.attr.StructEnclosingMethodAttribute; diff --git a/FernFlower-Patches/0008-LVT-Fixes-and-Support-for-Enhanced-For-loop-detectio.patch b/FernFlower-Patches/0008-LVT-Fixes-and-Support-for-Enhanced-For-loop-detectio.patch index a99ab53..bf8867f 100644 --- a/FernFlower-Patches/0008-LVT-Fixes-and-Support-for-Enhanced-For-loop-detectio.patch +++ b/FernFlower-Patches/0008-LVT-Fixes-and-Support-for-Enhanced-For-loop-detectio.patch @@ -158,7 +158,7 @@ index 80f024eb8e069cc4d208a9b79dbc7edf67161ec7..fa4b5ed56fa58f2d864ea3acd758a36f + } } diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 216db28b337c729ea839415bdccc3b48a1219709..5d0ec234807e0fa186ae88e7f74059710a47bd46 100644 +index 7d41769adee0974a02e0ef5a0518f9f9e53c8b58..bb2d0f0eb067a92472dcd8d69a0029d15c34c520 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -22,6 +22,7 @@ import org.jetbrains.java.decompiler.struct.StructField; @@ -374,7 +374,7 @@ index 216db28b337c729ea839415bdccc3b48a1219709..5d0ec234807e0fa186ae88e7f7405971 } } -@@ -913,4 +961,41 @@ public class NestedClassProcessor { +@@ -911,4 +959,41 @@ public class NestedClassProcessor { return fieldKey.hashCode() + varPair.hashCode(); } } @@ -1748,7 +1748,7 @@ index 0000000000000000000000000000000000000000..9123d92be14259e0117a0bb7b06a3d09 +} \ 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 d94561755621c6517976a763f8b9a0a4e49528e2..8d2ce0f8f4d4368f87ed596e4e76442ff97fed19 100644 +index 3cedf46af2faa91029231205455a1df1db7be3de..6776219b98b6b244bb9deda8cffc7b8fc63e4ac6 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -443,7 +443,7 @@ public class InvocationExprent extends Exprent { @@ -1760,7 +1760,7 @@ index d94561755621c6517976a763f8b9a0a4e49528e2..8d2ce0f8f4d4368f87ed596e4e76442f return !isStatic && parameters.size() == 0 && className.equals(UNBOXING_METHODS.get(name)); } -@@ -644,4 +644,4 @@ public class InvocationExprent extends Exprent { +@@ -643,4 +643,4 @@ public class InvocationExprent extends Exprent { return true; } @@ -1768,7 +1768,7 @@ index d94561755621c6517976a763f8b9a0a4e49528e2..8d2ce0f8f4d4368f87ed596e4e76442f \ No newline at end of file +} diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index 4c40e5152ffca092883170401453525093da011a..2fda2ba5fc05992faf891d2af14910023228c6b6 100644 +index 2b508a172340285dff5afa73cd4d7fcbf0dfeaff..8abfd33115391d24d08d349af9a5b64b1d75c1bf 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -9,11 +9,13 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; @@ -1872,7 +1872,7 @@ index 4c40e5152ffca092883170401453525093da011a..2fda2ba5fc05992faf891d2af1491002 MethodWrapper method = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); if (method != null) { Integer originalIndex = null; -@@ -196,6 +213,10 @@ public class VarExprent extends Exprent { +@@ -195,6 +212,10 @@ public class VarExprent extends Exprent { } public VarType getVarType() { @@ -1883,7 +1883,7 @@ index 4c40e5152ffca092883170401453525093da011a..2fda2ba5fc05992faf891d2af1491002 VarType vt = null; if (processor != null) { vt = processor.getVarType(getVarVersionPair()); -@@ -248,6 +269,93 @@ public class VarExprent extends Exprent { +@@ -247,6 +268,93 @@ public class VarExprent extends Exprent { this.stack = stack; } @@ -2004,7 +2004,7 @@ index a20acdff7d3ef1415fe6c90d05b92a90cfaf0073..6f21cd6df597613099861d874bb320ef // 0 - success, do nothing // 1 - cancel iteration diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java -index 592860d16b742ea70f85d2fe0270e2cbf5830f42..ccb7b3d9d0b38a5be9a6c9c727b4800bf815e715 100644 +index 552ae9594a64c737095bc5ec095e134926c1315c..234a42e3a73426204cf3debdb9b77c28f4afbb10 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java @@ -201,7 +201,7 @@ public class FlattenStatementsHelper { @@ -2095,7 +2095,7 @@ index 9498f3c548d18ead3bcbc076222bd5ace82b8275..e65af740228e237d3159cf4dd3398a9f //TODO: Cleanup/cache? diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -index 49729c1d27c1a1a42904949c25c0635f6a03a736..6f8a2619c728d168431673b14f53b94ba783cf2f 100644 +index 0113b76b89a886a96d8f1668142b008cb85ab637..f2c0589344ed69685dd3103d060109c700c7ee41 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java @@ -4,18 +4,28 @@ package org.jetbrains.java.decompiler.modules.decompiler.vars; @@ -2274,7 +2274,7 @@ index 49729c1d27c1a1a42904949c25c0635f6a03a736..6f8a2619c728d168431673b14f53b94b private Statement findFirstBlock(Statement stat, Integer varindex) { LinkedList stack = new LinkedList<>(); -@@ -250,6 +325,7 @@ public class VarDefinitionHelper { +@@ -249,6 +324,7 @@ public class VarDefinitionHelper { if (st.type == StatementType.DO) { DoStatement dost = (DoStatement)st; if (dost.getLoopType() != LoopType.FOR && @@ -2282,7 +2282,7 @@ index 49729c1d27c1a1a42904949c25c0635f6a03a736..6f8a2619c728d168431673b14f53b94b dost.getLoopType() != LoopType.DO) { currVars.add(dost.getConditionExprent()); } -@@ -320,7 +396,7 @@ public class VarDefinitionHelper { +@@ -319,7 +395,7 @@ public class VarDefinitionHelper { return res; } @@ -2291,7 +2291,7 @@ index 49729c1d27c1a1a42904949c25c0635f6a03a736..6f8a2619c728d168431673b14f53b94b if (expr.type == Exprent.EXPRENT_ASSIGNMENT) { Exprent left = ((AssignmentExprent)expr).getLeft(); if (left.type == Exprent.EXPRENT_VAR) { -@@ -333,4 +409,660 @@ public class VarDefinitionHelper { +@@ -332,4 +408,660 @@ public class VarDefinitionHelper { } return false; } diff --git a/FernFlower-Patches/0009-Rework-of-Generics-system-for-better-output.patch b/FernFlower-Patches/0009-Rework-of-Generics-system-for-better-output.patch index ddf3586..79bb0ea 100644 --- a/FernFlower-Patches/0009-Rework-of-Generics-system-for-better-output.patch +++ b/FernFlower-Patches/0009-Rework-of-Generics-system-for-better-output.patch @@ -34,7 +34,7 @@ index 4c4916e4cc5ccdd06dd4138dae54c31fb7f3bd34..decfe747ba2ab3643209987294ef7bcb \ No newline at end of file +} diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java -index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fcc99ec5b9 100644 +index 9b4e9fb3ab0a2f54c124c8a4c3943e6d7a5d01d2..31236841f1b4bf4f452f30d6b95f21fcc99ec5b9 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -371,9 +371,14 @@ public class ClassWriter { @@ -179,14 +179,13 @@ index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fc if (mask == null || mask.get(i) == null) { if (paramCount > 0) { buffer.append(", "); -@@ -765,24 +728,12 @@ public class ClassWriter { +@@ -765,23 +728,12 @@ public class ClassWriter { } String typeName; - boolean isVarArg = i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS); List typeParamAnnotations = TargetInfo.FormalParameterTarget.extract(typeAnnotations, i); -- if (paramType instanceof GenericType) { -- GenericType genParamType = (GenericType) paramType; +- if (paramType instanceof GenericType genParamType) { - isVarArg &= genParamType.getArrayDim() > 0; - if (isVarArg) { - genParamType = genParamType.decreaseArrayDim(); @@ -208,7 +207,7 @@ index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fc if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) && DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) { -@@ -801,7 +752,7 @@ public class ClassWriter { +@@ -800,7 +752,7 @@ public class ClassWriter { paramCount++; } @@ -217,7 +216,7 @@ index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fc } buffer.append(')'); -@@ -811,19 +762,14 @@ public class ClassWriter { +@@ -810,19 +762,14 @@ public class ClassWriter { throwsExceptions = true; buffer.append(" throws "); @@ -240,7 +239,7 @@ index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fc } } } -@@ -1051,7 +997,7 @@ public class ClassWriter { +@@ -1050,7 +997,7 @@ public class ClassWriter { final List typeAnnotations = TypeAnnotation.listFrom(cd); if (descriptor != null) { @@ -249,7 +248,7 @@ index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fc varArgComponent ? descriptor.type.decreaseArrayDim() : descriptor.type, TypeAnnotationWriteHelper.create(typeAnnotations) )); -@@ -1105,14 +1051,7 @@ public class ClassWriter { +@@ -1104,14 +1051,7 @@ public class ClassWriter { private static Map.Entry getFieldTypeData(StructField fd) { VarType fieldType = new VarType(fd.getDescriptor(), false); @@ -265,7 +264,7 @@ index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fc return new AbstractMap.SimpleImmutableEntry<>(fieldType, descriptor); } -@@ -1249,22 +1188,11 @@ public class ClassWriter { +@@ -1248,22 +1188,11 @@ public class ClassWriter { } } @@ -292,7 +291,7 @@ index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fc buffer.append('<'); for (int i = 0; i < parameters.size(); i++) { if (i > 0) { -@@ -1272,15 +1200,15 @@ public class ClassWriter { +@@ -1271,15 +1200,15 @@ public class ClassWriter { } TargetInfo.TypeParameterTarget.extract(typeAnnotations, i).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); buffer.append(parameters.get(i)); @@ -311,7 +310,7 @@ index 1989a01b158570651f332cf80dca0e0baeb4153c..31236841f1b4bf4f452f30d6b95f21fc } } } -@@ -1297,4 +1225,4 @@ public class ClassWriter { +@@ -1296,4 +1225,4 @@ public class ClassWriter { } } } @@ -493,7 +492,7 @@ index eb96762fa2174047a3f9dcecfb8c57bf4721c11f..dc3d20eed5ddcac36204fc9ed75d73c5 \ No newline at end of file +} diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -index 6cc60fd5314369cef21bd56c12e2af8e4c56292d..c713a4055dfc5aa05143a6cd856c5bd98e05c8c1 100644 +index 06567749310f70d0f3263a9b2bad4588237bdda9..ed470ffbbf57c7aea4e82174a99c8d31a097bc32 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java @@ -5,7 +5,6 @@ import org.jetbrains.java.decompiler.code.CodeConstants; @@ -545,7 +544,7 @@ index 6cc60fd5314369cef21bd56c12e2af8e4c56292d..c713a4055dfc5aa05143a6cd856c5bd9 buffer.append(condType == CONDITION_NONE ? " = " : OPERATORS[condType]).append(res); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -index b0c626320205e7e6fac1f8ceafdffbe89a5daf41..db2a53744ffeb8b0bdc7b045a822be2df1695b4e 100644 +index 54f6a306cd28f68879d25a536a1dea7a496a4aa3..9b9a0b4198688968201783fb804130a3312aa522 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java @@ -10,6 +10,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -594,7 +593,7 @@ index b0c626320205e7e6fac1f8ceafdffbe89a5daf41..db2a53744ffeb8b0bdc7b045a822be2d } return buffer; -@@ -141,6 +148,10 @@ public class ExitExprent extends Exprent { +@@ -140,6 +147,10 @@ public class ExitExprent extends Exprent { return retType; } @@ -774,7 +773,7 @@ index 67fc1f2beab815f0ca07ecf8a34b98fa23344749..33150f76d649f124bc818036b0f7c633 // IMatchable implementation // ***************************************************************************** diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -index 11669fe44ea78ab7322b82c844c8b220ca1a9975..b76d5dd1f39f3ef9a2847414bcf1cc3738b0fdae 100644 +index 379242393a83c6b3502a88c8d745a5b0bc1b5476..040e5d21985979a9686cb9fee6e3048fe87e5464 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -8,6 +8,8 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; @@ -823,7 +822,7 @@ index 11669fe44ea78ab7322b82c844c8b220ca1a9975..b76d5dd1f39f3ef9a2847414bcf1cc37 @Override public int getExprentUse() { return 0; // multiple references to a field considered dangerous in a multithreaded environment, thus no Exprent.MULTIPLE_USES set here -@@ -211,4 +235,4 @@ public class FieldExprent extends Exprent { +@@ -210,4 +234,4 @@ public class FieldExprent extends Exprent { return true; } @@ -831,7 +830,7 @@ index 11669fe44ea78ab7322b82c844c8b220ca1a9975..b76d5dd1f39f3ef9a2847414bcf1cc37 \ No newline at end of file +} diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index ac2b3a50e65c46ff998173335d505cdfc8a27b21..0a6281872ae535dbc0569cb08b301d58b6c5c9a3 100644 +index b2b26fb3f8b075182caee14d57b4cc351ffb120a..f18ef04b350a5f6d4599282aef5ea3f6e3dce778 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -2,6 +2,8 @@ @@ -906,7 +905,7 @@ index ac2b3a50e65c46ff998173335d505cdfc8a27b21..0a6281872ae535dbc0569cb08b301d58 @Override public int getExprentUse() { if (funcType >= FUNCTION_IMM && funcType <= FUNCTION_PPI) { -@@ -439,8 +481,12 @@ public class FunctionExprent extends Exprent { +@@ -438,8 +480,12 @@ public class FunctionExprent extends Exprent { case FUNCTION_BIT_NOT -> wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("~"); case FUNCTION_BOOL_NOT -> wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("!"); case FUNCTION_NEG -> wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("-"); @@ -921,7 +920,7 @@ index ac2b3a50e65c46ff998173335d505cdfc8a27b21..0a6281872ae535dbc0569cb08b301d58 case FUNCTION_ARRAY_LENGTH -> { Exprent arr = lstOperands.get(0); TextBuffer res = wrapOperandString(arr, false, indent, tracer); -@@ -571,7 +617,7 @@ public class FunctionExprent extends Exprent { +@@ -570,7 +616,7 @@ public class FunctionExprent extends Exprent { measureBytecode(values, lstOperands); measureBytecode(values); } @@ -931,7 +930,7 @@ index ac2b3a50e65c46ff998173335d505cdfc8a27b21..0a6281872ae535dbc0569cb08b301d58 // IMatchable implementation // ***************************************************************************** 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 8d2ce0f8f4d4368f87ed596e4e76442ff97fed19..6eab93e5ed261b0903ae3fe4677118bfa2d1d60e 100644 +index 6776219b98b6b244bb9deda8cffc7b8fc63e4ac6..2d8abaec74b301f76fcd4149600c1da72cc9b6c4 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -19,6 +19,8 @@ import org.jetbrains.java.decompiler.struct.consts.LinkConstant; @@ -1137,7 +1136,7 @@ index 8d2ce0f8f4d4368f87ed596e4e76442ff97fed19..6eab93e5ed261b0903ae3fe4677118bf ambiguous.set(i); break; diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -index 6df45768b067fd2e01ffd61bb157158cb369ad7e..2501863f7396c721a42eaab481b2c89d88209d23 100644 +index c47ae33d7d62a5049a89bb586032fc18bdc80173..2405fe08663102626f6ab007ccf5ee6c0e8922ea 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -14,7 +14,6 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; @@ -1219,7 +1218,7 @@ index 6df45768b067fd2e01ffd61bb157158cb369ad7e..2501863f7396c721a42eaab481b2c89d boolean firstParam = true; diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index 2fda2ba5fc05992faf891d2af14910023228c6b6..9ba49d3d3ee30e6e8db7cacd836f7f627ecb4b67 100644 +index 8abfd33115391d24d08d349af9a5b64b1d75c1bf..bbe17e0b2c4dcb7214e0c94cc34156e5c9f233a0 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -20,6 +20,7 @@ import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTypeTableAtt @@ -1284,7 +1283,7 @@ index 018d3fbdf53036db90b6c64e872098542133b630..d58218e0baa786456f15a14ef23a8d82 tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -index 6f8a2619c728d168431673b14f53b94ba783cf2f..abe421340550d258edce046fc901479fa027a23e 100644 +index f2c0589344ed69685dd3103d060109c700c7ee41..f9a7e55c108959b9696cb52cfd91aee341e40b06 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java @@ -24,7 +24,6 @@ import org.jetbrains.java.decompiler.struct.StructMethod; @@ -1295,7 +1294,7 @@ index 6f8a2619c728d168431673b14f53b94ba783cf2f..abe421340550d258edce046fc901479f import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; import java.util.*; -@@ -987,7 +986,7 @@ public class VarDefinitionHelper { +@@ -986,7 +985,7 @@ public class VarDefinitionHelper { private VarInfo(LocalVariable lvt, VarType type) { if (lvt != null && lvt.getSignature() != null) @@ -1693,7 +1692,7 @@ index e50983daf2a1bf6c93ec92c99221587d7c4f7c6a..11fa1a3e621221a09c0e611a7f912932 } } diff --git a/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java -index 7007b680a005a28a5d919e5e9e4298ed6c0ec566..49494925b2d67b95920bb2b8c8371e886341492f 100644 +index 267eb5067594bebb435f960b912754a5a2cff9e1..2096754661e845cfe3148d47c5c3ff914bcb0322 100644 --- a/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java +++ b/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java @@ -2,14 +2,24 @@ @@ -1757,7 +1756,7 @@ index 7007b680a005a28a5d919e5e9e4298ed6c0ec566..49494925b2d67b95920bb2b8c8371e88 public String buildNewDescriptor(NewClassNameBuilder builder) { boolean updated = false; -@@ -126,4 +165,4 @@ public final class MethodDescriptor { +@@ -125,4 +164,4 @@ public final class MethodDescriptor { result = 31 * result + params.length; return result; } @@ -1765,7 +1764,7 @@ index 7007b680a005a28a5d919e5e9e4298ed6c0ec566..49494925b2d67b95920bb2b8c8371e88 \ No newline at end of file +} diff --git a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java -index 30b31f5604f0c1566c536737aa7d9c61363e08c5..44d120256a8020b833567fe0f24c7b2c67caafde 100644 +index 2d18843b486376752fa29c03cec82308e9440bf5..f4115448cfa13ba37fb1ee1795903ffb0c79a6af 100644 --- a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java +++ b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java @@ -3,6 +3,7 @@ package org.jetbrains.java.decompiler.struct.gen; @@ -1819,7 +1818,7 @@ index 30b31f5604f0c1566c536737aa7d9c61363e08c5..44d120256a8020b833567fe0f24c7b2c @Override public boolean equals(Object o) { if (o == this) { -@@ -374,4 +384,15 @@ public class VarType implements Type { // TODO: optimize switch +@@ -373,4 +383,15 @@ public class VarType implements Type { // TODO: optimize switch default -> throw new IllegalArgumentException("Invalid type: " + c); }; } diff --git a/FernFlower-Patches/0010-Improvements-to-var-and-var.patch b/FernFlower-Patches/0010-Improvements-to-var-and-var.patch index 46d95a3..040d37c 100644 --- a/FernFlower-Patches/0010-Improvements-to-var-and-var.patch +++ b/FernFlower-Patches/0010-Improvements-to-var-and-var.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Improvements to var++ and var-- diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 5d0ec234807e0fa186ae88e7f74059710a47bd46..866cea112a60907c3ef02160a3b6c0bac1a075ae 100644 +index bb2d0f0eb067a92472dcd8d69a0029d15c34c520..fde1c3bca1b12454b6f9a692c5f870ba946a590e 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -@@ -916,7 +916,7 @@ public class NestedClassProcessor { +@@ -915,7 +915,7 @@ public class NestedClassProcessor { case Exprent.EXPRENT_FIELD -> res = classname.equals(((FieldExprent)expr).getClassname()); case Exprent.EXPRENT_INVOCATION -> res = classname.equals(((InvocationExprent)expr).getClassName()); case Exprent.EXPRENT_NEW -> { @@ -114,10 +114,10 @@ index 81b4c480810a2f74388a4626a4dc0c2bfc523365..f0f66146eb4ecad4ed1bbd41712cace8 } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index 56745ac71bbff7cbf8353579cd09f7482206677f..311fe8507fba664bd4b1e627f8ffbdb4c0c97cab 100644 +index b0bda600031b4cc52b6b083d5afd07a92ccef1af..401917e6947c0ae541c966777cf2deddf54ed644 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -@@ -501,7 +501,12 @@ public class ConstExprent extends Exprent { +@@ -500,7 +500,12 @@ public class ConstExprent extends Exprent { public void getBytecodeRange(BitSet values) { measureBytecode(values); } diff --git a/FernFlower-Patches/0011-JAD-Style-variable-naming.patch b/FernFlower-Patches/0011-JAD-Style-variable-naming.patch index df4721b..1a30eab 100644 --- a/FernFlower-Patches/0011-JAD-Style-variable-naming.patch +++ b/FernFlower-Patches/0011-JAD-Style-variable-naming.patch @@ -60,7 +60,7 @@ index 31236841f1b4bf4f452f30d6b95f21fcc99ec5b9..aa990406ef8d91838aa2d928bdfb183f firstParameter = false; } diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index 9104ad3f1edae3deb11913bb08d101269370ca7d..7149145b1f3ed3583f8bbe416947a0d68de523db 100644 +index 8173ecd04da97e5e9a8f5f9a2e309726439697e0..3398f884985021a324fc5ae6ac6a461f8e5b2f33 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -146,6 +146,7 @@ public class ClassesProcessor implements CodeConstants { @@ -105,15 +105,6 @@ index 9104ad3f1edae3deb11913bb08d101269370ca7d..7149145b1f3ed3583f8bbe416947a0d6 for (ClassNode nd : node.nested) { destroyWrappers(nd); -@@ -500,7 +521,7 @@ public class ClassesProcessor implements CodeConstants { - - anonymousClassType = new VarType(lambda_class_name, true); - -- boolean is_method_reference = (content_class_name != classStruct.qualifiedName); -+ boolean is_method_reference = !classStruct.qualifiedName.equals(content_class_name); - if (!is_method_reference) { // content method in the same class, check synthetic flag - StructMethod mt = classStruct.getMethod(content_method_name, content_method_descriptor); - is_method_reference = !mt.isSynthetic(); // if not synthetic -> method reference @@ -563,4 +584,4 @@ public class ClassesProcessor implements CodeConstants { public boolean is_content_method_static; } @@ -373,7 +364,7 @@ index c1126a2b7559e2f8a69a54ee0b7db2ceda3d9776..964bff5a00b35969fa08e48ca355801f if (attr != null) { // only param names here diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -index abe421340550d258edce046fc901479fa027a23e..cf7f00021cad6818e144342dcbf5b6198e8adeb3 100644 +index f9a7e55c108959b9696cb52cfd91aee341e40b06..b35985211d1f0488f76cbd6e87f18e3732b2d589 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java @@ -2,6 +2,7 @@ @@ -400,7 +391,7 @@ index abe421340550d258edce046fc901479fa027a23e..cf7f00021cad6818e144342dcbf5b619 import java.util.*; import java.util.Map.Entry; -@@ -843,6 +846,53 @@ public class VarDefinitionHelper { +@@ -842,6 +845,53 @@ public class VarDefinitionHelper { for (Entry e : types.entrySet()) { typeNames.put(e.getKey(), e.getValue().getCast()); } @@ -454,7 +445,7 @@ index abe421340550d258edce046fc901479fa027a23e..cf7f00021cad6818e144342dcbf5b619 Map lvts = new HashMap<>(); for (Entry e : types.entrySet()) { -@@ -852,7 +902,16 @@ public class VarDefinitionHelper { +@@ -851,7 +901,16 @@ public class VarDefinitionHelper { continue; } LocalVariable lvt = e.getValue().getLVT(); @@ -471,7 +462,7 @@ index abe421340550d258edce046fc901479fa027a23e..cf7f00021cad6818e144342dcbf5b619 varproc.setVarLVT(idx, lvt); lvts.put(idx, lvt); } -@@ -986,7 +1045,7 @@ public class VarDefinitionHelper { +@@ -985,7 +1044,7 @@ public class VarDefinitionHelper { private VarInfo(LocalVariable lvt, VarType type) { if (lvt != null && lvt.getSignature() != null) diff --git a/FernFlower-Patches/0012-Fix-primitive-un-boxing-issues.patch b/FernFlower-Patches/0012-Fix-primitive-un-boxing-issues.patch index 3fa637f..80cad44 100644 --- a/FernFlower-Patches/0012-Fix-primitive-un-boxing-issues.patch +++ b/FernFlower-Patches/0012-Fix-primitive-un-boxing-issues.patch @@ -30,10 +30,10 @@ index e005b2941b4e76b736b8d00905726ac8500c3dc2..bc8c421206b44539c2f2da859658102f } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index 0a6281872ae535dbc0569cb08b301d58b6c5c9a3..513ae5c2d5e1674694e86701e507c1e46c2f031b 100644 +index f18ef04b350a5f6d4599282aef5ea3f6e3dce778..ec2d6931c9426913680fd2ec180483389d96ac4b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -@@ -534,6 +534,19 @@ public class FunctionExprent extends Exprent { +@@ -533,6 +533,19 @@ public class FunctionExprent extends Exprent { .append(")"); default -> { assert funcType <= FUNCTION_I2S; @@ -54,7 +54,7 @@ index 0a6281872ae535dbc0569cb08b301d58b6c5c9a3..513ae5c2d5e1674694e86701e507c1e4 TYPES[funcType - FUNCTION_I2L], Collections.emptyList()) + ")"); } 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 6eab93e5ed261b0903ae3fe4677118bfa2d1d60e..7ebc36c1de0265db791b47b9558c41e303a3d7b2 100644 +index 2d8abaec74b301f76fcd4149600c1da72cc9b6c4..d51f0eba4a80cad4159a5135b2d87b8d405c0ed9 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -59,6 +59,8 @@ public class InvocationExprent extends Exprent { diff --git a/FernFlower-Patches/0017-Enhance-Generic-Invocations-Temporarily.patch b/FernFlower-Patches/0017-Enhance-Generic-Invocations-Temporarily.patch index 55fb93d..dcd2dfe 100644 --- a/FernFlower-Patches/0017-Enhance-Generic-Invocations-Temporarily.patch +++ b/FernFlower-Patches/0017-Enhance-Generic-Invocations-Temporarily.patch @@ -24,7 +24,7 @@ index 33150f76d649f124bc818036b0f7c6331d5e74be..e2f36231b51e547b4aae610c8450d83b left = left.resizeArrayDim(0); right = right.resizeArrayDim(0); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index 513ae5c2d5e1674694e86701e507c1e46c2f031b..cb80c8d7be08b9f3d6770541910832bb3d9a58a9 100644 +index ec2d6931c9426913680fd2ec180483389d96ac4b..cb15c8bc3d924e99c0bf9db350e8fe102bc5f97a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -278,11 +278,11 @@ public class FunctionExprent extends Exprent { @@ -57,7 +57,7 @@ index 513ae5c2d5e1674694e86701e507c1e46c2f031b..cb80c8d7be08b9f3d6770541910832bb } else { //TODO: Capture generics to make cast better? this.needsCast = right.getType() == CodeConstants.TYPE_NULL || !DecompilerContext.getStructContext().instanceOf(right.getValue(), cast.getValue()); -@@ -644,4 +653,4 @@ public class FunctionExprent extends Exprent { +@@ -643,4 +652,4 @@ public class FunctionExprent extends Exprent { Integer type = (Integer)matchNode.getRuleValue(MatchProperties.EXPRENT_FUNCTYPE); return type == null || this.funcType == type; } @@ -65,7 +65,7 @@ index 513ae5c2d5e1674694e86701e507c1e46c2f031b..cb80c8d7be08b9f3d6770541910832bb \ 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 7ebc36c1de0265db791b47b9558c41e303a3d7b2..28bae14b7342dd6897e638889682178248039ad7 100644 +index d51f0eba4a80cad4159a5135b2d87b8d405c0ed9..f23110233f59728ab4b700bfc0fa2b625f0d7071 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -399,6 +399,7 @@ public class InvocationExprent extends Exprent { diff --git a/FernFlower-Patches/0021-Synthetic-getClass-Objects.requireNonNull-cleanup.patch b/FernFlower-Patches/0021-Synthetic-getClass-Objects.requireNonNull-cleanup.patch index f86925c..4afe873 100644 --- a/FernFlower-Patches/0021-Synthetic-getClass-Objects.requireNonNull-cleanup.patch +++ b/FernFlower-Patches/0021-Synthetic-getClass-Objects.requireNonNull-cleanup.patch @@ -135,7 +135,7 @@ index dc3d20eed5ddcac36204fc9ed75d73c53a8c9805..efa677ae6cfdc08635eff080c7241ec0 private static boolean isConstructorInvocationRemote(List list, int index) { Exprent current = list.get(index); 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 28bae14b7342dd6897e638889682178248039ad7..eda61adada8942006a5a49d5f0905ba010505fea 100644 +index f23110233f59728ab4b700bfc0fa2b625f0d7071..c77ac2f2e4f8936c131f932940878fab9f5c2eb8 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -61,6 +61,7 @@ public class InvocationExprent extends Exprent { @@ -154,7 +154,7 @@ index 28bae14b7342dd6897e638889682178248039ad7..eda61adada8942006a5a49d5f0905ba0 } @Override -@@ -955,6 +957,14 @@ public class InvocationExprent extends Exprent { +@@ -954,6 +956,14 @@ public class InvocationExprent extends Exprent { return bootstrapArguments; } diff --git a/FernFlower-Patches/0023-Give-nicer-output-for-float-and-double-literals.patch b/FernFlower-Patches/0023-Give-nicer-output-for-float-and-double-literals.patch index ef7c128..980223a 100644 --- a/FernFlower-Patches/0023-Give-nicer-output-for-float-and-double-literals.patch +++ b/FernFlower-Patches/0023-Give-nicer-output-for-float-and-double-literals.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Give nicer output for float and double literals diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index 311fe8507fba664bd4b1e627f8ffbdb4c0c97cab..da281b179a137434b55171d69266a039c7c1f6f1 100644 +index 401917e6947c0ae541c966777cf2deddf54ed644..f0c519aa31ca4ca83dac02d1bf729ff67e9e8992 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java @@ -48,6 +48,81 @@ public class ConstExprent extends Exprent { diff --git a/FernFlower-Patches/0024-Add-try-with-resource-support.patch b/FernFlower-Patches/0024-Add-try-with-resource-support.patch index 59abf10..cab16c1 100644 --- a/FernFlower-Patches/0024-Add-try-with-resource-support.patch +++ b/FernFlower-Patches/0024-Add-try-with-resource-support.patch @@ -749,7 +749,7 @@ index 0000000000000000000000000000000000000000..cdd05cd3d40ad85380e00ddeba7e2894 + } +} diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java -index ccb7b3d9d0b38a5be9a6c9c727b4800bf815e715..99fc1c604cadabc1f106a3be745980b1e9b3ad3f 100644 +index 234a42e3a73426204cf3debdb9b77c28f4afbb10..940d41923c8df57fd82cf4b42c2a38d523f7e0c3 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java @@ -128,6 +128,13 @@ public class FlattenStatementsHelper { @@ -888,7 +888,7 @@ index 7c83c48777e2dc683d1321fb297f89466f62e8ce..97c1d3f816dcfc21811da2097744bfe9 + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -index cf7f00021cad6818e144342dcbf5b6198e8adeb3..ad32facfe21c854c69c16ee51aa885b8c266d7b9 100644 +index b35985211d1f0488f76cbd6e87f18e3732b2d589..13d023de573ced3cde29f9b42212051a47232733 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java @@ -110,7 +110,11 @@ public class VarDefinitionHelper { diff --git a/FernFlower-Patches/0025-Prioritize-self-and-enclosing-class-when-encounterin.patch b/FernFlower-Patches/0025-Prioritize-self-and-enclosing-class-when-encounterin.patch index 12206a1..5d0ed68 100644 --- a/FernFlower-Patches/0025-Prioritize-self-and-enclosing-class-when-encounterin.patch +++ b/FernFlower-Patches/0025-Prioritize-self-and-enclosing-class-when-encounterin.patch @@ -23,7 +23,7 @@ index 0fb12b6d99f3c1dc7652e5ab49e36683d7a6db08..6f2f8419d41a240c6d1428be0b0ca925 TextBuffer buffer, List parameters, diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index 7149145b1f3ed3583f8bbe416947a0d68de523db..2c67a4fbcdf011cc91b9166f616feb27ce9dcd4c 100644 +index 3398f884985021a324fc5ae6ac6a461f8e5b2f33..921b3b653743ff77dead340be940fcef759bcead 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -41,10 +41,20 @@ public class ClassesProcessor implements CodeConstants { diff --git a/FernFlower-Patches/0026-Fix-ambiguous-lambdas.patch b/FernFlower-Patches/0026-Fix-ambiguous-lambdas.patch index 82d1c42..c57c3e1 100644 --- a/FernFlower-Patches/0026-Fix-ambiguous-lambdas.patch +++ b/FernFlower-Patches/0026-Fix-ambiguous-lambdas.patch @@ -41,7 +41,7 @@ index f7e086c560b6e1e5d67d93813c91ecc70db49ce1..c5b8af9d9047d9c06840dfcb95e18a87 + } } 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 eda61adada8942006a5a49d5f0905ba010505fea..01ce4f5c3d827e51934de816723ccac236ed9e18 100644 +index c77ac2f2e4f8936c131f932940878fab9f5c2eb8..165a152ea68e6b6580a9064bd1f4a4d39677f972 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -791,7 +791,8 @@ public class InvocationExprent extends Exprent { @@ -95,7 +95,7 @@ index eda61adada8942006a5a49d5f0905ba010505fea..01ce4f5c3d827e51934de816723ccac2 MethodDescriptor md = MethodDescriptor.parseDescriptor(mtt.getDescriptor()); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -index 2501863f7396c721a42eaab481b2c89d88209d23..5ee4fb58a5687a0e26558fbc4fdaa989695bc6fa 100644 +index 2405fe08663102626f6ab007ccf5ee6c0e8922ea..049bf247002da65a90392f054ad2c57a04ebae81 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -5,6 +5,8 @@ import org.jetbrains.java.decompiler.code.CodeConstants; @@ -133,7 +133,7 @@ index 2501863f7396c721a42eaab481b2c89d88209d23..5ee4fb58a5687a0e26558fbc4fdaa989 } } } -@@ -511,4 +515,17 @@ public class NewExprent extends Exprent { +@@ -510,4 +514,17 @@ public class NewExprent extends Exprent { public void setEnumConst(boolean enumConst) { this.enumConst = enumConst; } diff --git a/FernFlower-Patches/0027-Fix-field-initalizers.patch b/FernFlower-Patches/0027-Fix-field-initalizers.patch index b988b9d..1c3a634 100644 --- a/FernFlower-Patches/0027-Fix-field-initalizers.patch +++ b/FernFlower-Patches/0027-Fix-field-initalizers.patch @@ -249,7 +249,7 @@ index b44a78019f0717213822ef5572c5d7ecde6d4ee3..20d3f0391343689eb604b8b953cabb26 + } +} diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -index b76d5dd1f39f3ef9a2847414bcf1cc3738b0fdae..be789c6f999339fc4d755850dfd888f600f73a45 100644 +index 040e5d21985979a9686cb9fee6e3048fe87e5464..e98b53eb94ed7f1f5c936887be8418e6637b2b43 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -33,18 +33,24 @@ public class FieldExprent extends Exprent { @@ -286,7 +286,7 @@ index b76d5dd1f39f3ef9a2847414bcf1cc3738b0fdae..be789c6f999339fc4d755850dfd888f6 buf.append(DecompilerContext.getImportCollector().getNestedNameInClassContext(ExprProcessor.buildJavaClassName(classname))); buf.append("."); } -@@ -207,6 +213,10 @@ public class FieldExprent extends Exprent { +@@ -206,6 +212,10 @@ public class FieldExprent extends Exprent { return name; } diff --git a/FernFlower-Patches/0028-Improve-inferred-generic-types.patch b/FernFlower-Patches/0028-Improve-inferred-generic-types.patch index adcffd2..879c65a 100644 --- a/FernFlower-Patches/0028-Improve-inferred-generic-types.patch +++ b/FernFlower-Patches/0028-Improve-inferred-generic-types.patch @@ -25,7 +25,7 @@ index 53349248a038cea0ef82cdc2138ca93e722d1d06..a25566f0e6ba9a4f67c6412fc379874f defaults.put(LOG_LEVEL, IFernflowerLogger.Severity.INFO.name()); defaults.put(MAX_PROCESSING_METHOD, "0"); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java -index 88b429ca3bc60303f9075eab36e279f9c58f4520..b03bcfc45ba7d58bcfc92612460c7f3de4bab1e4 100644 +index 406848324e427a2b18d3666e321172f0f130ec4c..e14e8821ea5e7642ff49b04eb4cf1e4d0aa32190 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java @@ -39,6 +39,17 @@ public class ArrayExprent extends Exprent { @@ -47,7 +47,7 @@ index 88b429ca3bc60303f9075eab36e279f9c58f4520..b03bcfc45ba7d58bcfc92612460c7f3d public int getExprentUse() { return array.getExprentUse() & index.getExprentUse() & Exprent.MULTIPLE_USES; diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index da281b179a137434b55171d69266a039c7c1f6f1..6526b901bc08d5b3a21f0ee3ea31661d86d23799 100644 +index f0c519aa31ca4ca83dac02d1bf729ff67e9e8992..df602b646b7ab2b6f13c42617634f334f828cc0e 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java @@ -4,6 +4,7 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; @@ -181,7 +181,7 @@ index e2f36231b51e547b4aae610c8450d83bc0952e44..0509360d7637650341acca72e72e4902 // IMatchable implementation // ***************************************************************************** diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -index be789c6f999339fc4d755850dfd888f600f73a45..66ea2304968dae841fdd736c81e7332c75d9ecd5 100644 +index e98b53eb94ed7f1f5c936887be8418e6637b2b43..3099a4611a01341d3a923d84723303ed0e76741b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -14,6 +14,7 @@ import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribu @@ -231,7 +231,7 @@ index be789c6f999339fc4d755850dfd888f600f73a45..66ea2304968dae841fdd736c81e7332c return getExprType(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index cb80c8d7be08b9f3d6770541910832bb3d9a58a9..c2136584b0ae2a5c7ba34370666bd8b5f4276aaa 100644 +index cb15c8bc3d924e99c0bf9db350e8fe102bc5f97a..e74a3c65c126f3378a4551bc96dd82aff9dc4601 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -316,6 +316,11 @@ public class FunctionExprent extends Exprent { @@ -246,7 +246,7 @@ index cb80c8d7be08b9f3d6770541910832bb3d9a58a9..c2136584b0ae2a5c7ba34370666bd8b5 return getExprType(); } -@@ -634,6 +639,17 @@ public class FunctionExprent extends Exprent { +@@ -633,6 +638,17 @@ public class FunctionExprent extends Exprent { this.implicitType = implicitType; } @@ -265,7 +265,7 @@ index cb80c8d7be08b9f3d6770541910832bb3d9a58a9..c2136584b0ae2a5c7ba34370666bd8b5 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 01ce4f5c3d827e51934de816723ccac236ed9e18..962b7a9b85ef5fd29bce0c2953748a6cd3a87ea7 100644 +index 165a152ea68e6b6580a9064bd1f4a4d39677f972..1661a1deb02a4caa5238b5342e5d6043e4e37b7b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -32,6 +32,7 @@ import org.jetbrains.java.decompiler.util.TextUtil; @@ -962,7 +962,7 @@ index 01ce4f5c3d827e51934de816723ccac236ed9e18..962b7a9b85ef5fd29bce0c2953748a6c @Override public void replaceExprent(Exprent oldExpr, Exprent newExpr) { if (oldExpr == instance) { -@@ -981,6 +1443,19 @@ public class InvocationExprent extends Exprent { +@@ -980,6 +1442,19 @@ public class InvocationExprent extends Exprent { return isSyntheticNullCheck; } @@ -983,7 +983,7 @@ index 01ce4f5c3d827e51934de816723ccac236ed9e18..962b7a9b85ef5fd29bce0c2953748a6c public void getBytecodeRange(BitSet values) { measureBytecode(values, parameters); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -index 5ee4fb58a5687a0e26558fbc4fdaa989695bc6fa..8d68274e8cb064cb94365eb36df65772f8bdb54a 100644 +index 049bf247002da65a90392f054ad2c57a04ebae81..72205fbd81840cda91ca303d15758df4a2e79699 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -5,7 +5,16 @@ import org.jetbrains.java.decompiler.code.CodeConstants; @@ -1429,7 +1429,7 @@ index 5ee4fb58a5687a0e26558fbc4fdaa989695bc6fa..8d68274e8cb064cb94365eb36df65772 @Override public void replaceExprent(Exprent oldExpr, Exprent newExpr) { if (oldExpr == constructor) { -@@ -528,4 +793,11 @@ public class NewExprent extends Exprent { +@@ -527,4 +792,11 @@ public class NewExprent extends Exprent { } return ""; } @@ -1442,7 +1442,7 @@ index 5ee4fb58a5687a0e26558fbc4fdaa989695bc6fa..8d68274e8cb064cb94365eb36df65772 + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index 9ba49d3d3ee30e6e8db7cacd836f7f627ecb4b67..4f8602a2c55bc1be876d254346fdc38b15c5a2f5 100644 +index bbe17e0b2c4dcb7214e0c94cc34156e5c9f233a0..e7bb1eb49b73102af8f967b7d5d3dbed5a1fc86a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -13,6 +13,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; @@ -1453,7 +1453,7 @@ index 9ba49d3d3ee30e6e8db7cacd836f7f627ecb4b67..4f8602a2c55bc1be876d254346fdc38b import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute; import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute.LocalVariable; -@@ -236,7 +237,21 @@ public class VarExprent extends Exprent { +@@ -235,7 +236,21 @@ public class VarExprent extends Exprent { VarType vt = null; if (processor != null) { @@ -1547,10 +1547,10 @@ index 1274df19dd56bf8061384af8d3db78856f836928..80ad6c5234031d18947bebfb87eda789 for (String line : string.split("\n")) { String[] pts = line.split(" "); diff --git a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java -index 44d120256a8020b833567fe0f24c7b2c67caafde..1aabd99f31376417b6b72f3150af3823b04f9de8 100644 +index f4115448cfa13ba37fb1ee1795903ffb0c79a6af..d089b8180169910658f302a143d3372137f735c2 100644 --- a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java +++ b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java -@@ -390,8 +390,10 @@ public class VarType implements Type { // TODO: optimize switch +@@ -389,8 +389,10 @@ public class VarType implements Type { // TODO: optimize switch } public VarType remap(Map map) { diff --git a/FernFlower-Patches/0029-Improve-stack-var-processor-output.patch b/FernFlower-Patches/0029-Improve-stack-var-processor-output.patch index 57e1138..064adcf 100644 --- a/FernFlower-Patches/0029-Improve-stack-var-processor-output.patch +++ b/FernFlower-Patches/0029-Improve-stack-var-processor-output.patch @@ -24,7 +24,7 @@ index 4713a0212ee1ae4cc269dd24f2227a91a2c9beed..9ae846d540337db99dc054ec1a43271e if (TryHelper.enhanceTryStats(root, mt)) { diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 866cea112a60907c3ef02160a3b6c0bac1a075ae..1b2401d38d63dcca4eb4b4d7ed24aa23da9c98fb 100644 +index fde1c3bca1b12454b6f9a692c5f870ba946a590e..95db638383c843bf01df05daf2d94240cfe5ebc8 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -141,6 +141,9 @@ public class NestedClassProcessor { @@ -318,7 +318,7 @@ index d8fd9bdf784704836e69cfdd1596ae29b2732232..139ccdb55347a5d66627c1489ee73910 + } } 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 962b7a9b85ef5fd29bce0c2953748a6cd3a87ea7..ee533a7ab76350ce982406120e439919070fa18f 100644 +index 1661a1deb02a4caa5238b5342e5d6043e4e37b7b..4633697497baaa977d1f5451c5340eae3769472f 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -162,6 +162,11 @@ public class InvocationExprent extends Exprent { @@ -334,7 +334,7 @@ index 962b7a9b85ef5fd29bce0c2953748a6cd3a87ea7..ee533a7ab76350ce982406120e439919 @Override diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index 4f8602a2c55bc1be876d254346fdc38b15c5a2f5..135c633ac8ed35d6ccb4d24131395ec6d94ea566 100644 +index e7bb1eb49b73102af8f967b7d5d3dbed5a1fc86a..8807a1534a587af70c2779f2bf8f7cdf3ec9d7f2 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -46,6 +46,7 @@ public class VarExprent extends Exprent { @@ -353,7 +353,7 @@ index 4f8602a2c55bc1be876d254346fdc38b15c5a2f5..135c633ac8ed35d6ccb4d24131395ec6 return var; } -@@ -312,6 +314,14 @@ public class VarExprent extends Exprent { +@@ -311,6 +313,14 @@ public class VarExprent extends Exprent { return lvt; } @@ -564,7 +564,7 @@ index 5e1e323a6e2043d776c513e800056be200ab2971..0262a3378080ce4a283ee12a44d11e92 + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -index ad32facfe21c854c69c16ee51aa885b8c266d7b9..c4c7253e1062be0bae6a15dbd02678ee7c36fee7 100644 +index 13d023de573ced3cde29f9b42212051a47232733..347ba24dbcc6a530307d9a1d4eae946efa1dfac6 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java @@ -11,6 +11,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent; @@ -583,7 +583,7 @@ index ad32facfe21c854c69c16ee51aa885b8c266d7b9..c4c7253e1062be0bae6a15dbd02678ee } -@@ -1127,4 +1129,79 @@ public class VarDefinitionHelper { +@@ -1126,4 +1128,79 @@ public class VarDefinitionHelper { } return false; } diff --git a/FernFlower-Patches/0032-Add-explicit-cast-to-invocations-of-java-nio-Buffer-.patch b/FernFlower-Patches/0032-Add-explicit-cast-to-invocations-of-java-nio-Buffer-.patch index 5fc2440..c6c2647 100644 --- a/FernFlower-Patches/0032-Add-explicit-cast-to-invocations-of-java-nio-Buffer-.patch +++ b/FernFlower-Patches/0032-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 ee533a7ab76350ce982406120e439919070fa18f..fd4fb8c060432591710e25e2941d99c538b547b6 100644 +index 4633697497baaa977d1f5451c5340eae3769472f..1a3bd9c6b051447ef2aca98b58ff70b3b89da52c 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -47,6 +47,8 @@ public class InvocationExprent extends Exprent { diff --git a/FernFlower-Patches/0033-Revert-change-to-FieldExprent-getExprentUse.patch b/FernFlower-Patches/0033-Revert-change-to-FieldExprent-getExprentUse.patch index c39036d..8624781 100644 --- a/FernFlower-Patches/0033-Revert-change-to-FieldExprent-getExprentUse.patch +++ b/FernFlower-Patches/0033-Revert-change-to-FieldExprent-getExprentUse.patch @@ -7,7 +7,7 @@ Revert part of a change introduced upstream. https://github.com/MinecraftForge/F This upstream change causes local variables to not be inlined in many cases, and makes decomp very messy for the reason of 'thread safety'. diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -index 66ea2304968dae841fdd736c81e7332c75d9ecd5..e6e3e9d6f50239c716d285d64f37679bbf0ff553 100644 +index 3099a4611a01341d3a923d84723303ed0e76741b..34ee7377dfef29d73f4cd0e5bf53944befafbd7d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -105,7 +105,13 @@ public class FieldExprent extends Exprent { diff --git a/FernFlower-Patches/0034-Add-only-argument-It-will-filter-what-classes-are-de.patch b/FernFlower-Patches/0034-Add-only-argument-It-will-filter-what-classes-are-de.patch index 87bdb01..63b4c60 100644 --- a/FernFlower-Patches/0034-Add-only-argument-It-will-filter-what-classes-are-de.patch +++ b/FernFlower-Patches/0034-Add-only-argument-It-will-filter-what-classes-are-de.patch @@ -8,7 +8,7 @@ Uses a prefix system, so -only=net/minecraft/block/ will decompile all classes i Useful for debugging to limit scope/runtime. diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index 2c67a4fbcdf011cc91b9166f616feb27ce9dcd4c..3e168efbd10b661519a01fb48a3aabc16460f840 100644 +index 921b3b653743ff77dead340be940fcef759bcead..ff19c7105c0e6bcfa280dca8255eaf32357a2fc3 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -36,6 +36,7 @@ public class ClassesProcessor implements CodeConstants { diff --git a/FernFlower-Patches/0036-Do-not-rebuild-variable-names-in-lambdas.patch b/FernFlower-Patches/0036-Do-not-rebuild-variable-names-in-lambdas.patch index c941329..ac30e63 100644 --- a/FernFlower-Patches/0036-Do-not-rebuild-variable-names-in-lambdas.patch +++ b/FernFlower-Patches/0036-Do-not-rebuild-variable-names-in-lambdas.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Do not rebuild variable names in lambdas. Breaks outer this references. Code existed before my time, no idea what it's intention is. diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 1b2401d38d63dcca4eb4b4d7ed24aa23da9c98fb..5a52b4d9b2c4810cceeb7df3e2271a3dd6ddbe7f 100644 +index 95db638383c843bf01df05daf2d94240cfe5ebc8..1518aae1cf006454e11471b52c54267991b65596 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -163,7 +163,7 @@ public class NestedClassProcessor { diff --git a/FernFlower-Patches/0037-Add-toString-to-MethodDescriptor.patch b/FernFlower-Patches/0037-Add-toString-to-MethodDescriptor.patch index 20145cd..305ca18 100644 --- a/FernFlower-Patches/0037-Add-toString-to-MethodDescriptor.patch +++ b/FernFlower-Patches/0037-Add-toString-to-MethodDescriptor.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add toString to MethodDescriptor diff --git a/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java -index 49494925b2d67b95920bb2b8c8371e886341492f..9b0d6157a3827b0b269a4e396cd91ff93bdf2261 100644 +index 2096754661e845cfe3148d47c5c3ff914bcb0322..c033ae3122302a16f760df24110ab3dd07e39852 100644 --- a/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java +++ b/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java @@ -19,11 +19,13 @@ import java.util.Objects; diff --git a/FernFlower-Patches/0038-Make-decomp-threaded.patch b/FernFlower-Patches/0038-Make-decomp-threaded.patch index 2b9d615..f5af630 100644 --- a/FernFlower-Patches/0038-Make-decomp-threaded.patch +++ b/FernFlower-Patches/0038-Make-decomp-threaded.patch @@ -7,7 +7,7 @@ Subject: [PATCH] Make decomp threaded `-thr AUTO` to auto select, (default) diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index 3e168efbd10b661519a01fb48a3aabc16460f840..573e8342b16e51b8c9a945b4513657c6f64f17c2 100644 +index ff19c7105c0e6bcfa280dca8255eaf32357a2fc3..a1629d28780be9743ab816b5ffbfe664291008a3 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -30,12 +30,13 @@ import org.jetbrains.java.decompiler.util.TextBuffer; diff --git a/FernFlower-Patches/0040-Fixup-J9-string-concat.patch b/FernFlower-Patches/0040-Fixup-J9-string-concat.patch index 9ea99da..8cff824 100644 --- a/FernFlower-Patches/0040-Fixup-J9-string-concat.patch +++ b/FernFlower-Patches/0040-Fixup-J9-string-concat.patch @@ -20,7 +20,7 @@ index 9ae846d540337db99dc054ec1a43271e2d41ab7d..74532a087d53613065490b1bd3bf5457 LabelHelper.cleanUpEdges(root); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java -index d85dead7cab48a9f551cb1226ef952807a067ec8..2aa9f91fc062ba76939d915428e84f6183fb7f71 100644 +index 5d47c847133cf0413365eddd5f1a2104b2f6ac6b..2aa9f91fc062ba76939d915428e84f6183fb7f71 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java @@ -4,6 +4,7 @@ package org.jetbrains.java.decompiler.modules.decompiler; @@ -78,12 +78,11 @@ index d85dead7cab48a9f551cb1226ef952807a067ec8..2aa9f91fc062ba76939d915428e84f61 for (int i = 0; i < recipe.length(); i++) { char c = recipe.charAt(i); -@@ -173,13 +207,12 @@ public final class ConcatenationHelper { +@@ -173,12 +207,12 @@ public final class ConcatenationHelper { if (c == TAG_ARG) { Exprent exprent = parameters.get(parameterId++); -- if ((exprent instanceof VarExprent) && res.isEmpty()) { -- VarExprent varExprent = (VarExprent) exprent; +- if ((exprent instanceof VarExprent varExprent) && res.isEmpty()) { - - if (!VarType.VARTYPE_STRING.equals(varExprent.getVarType())) { - // First item of concatenation is a variable and variable's type is not a String. diff --git a/FernFlower-Patches/0044-Search-generics-when-finding-where-to-inject-local-c.patch b/FernFlower-Patches/0044-Search-generics-when-finding-where-to-inject-local-c.patch index 693af80..51c7254 100644 --- a/FernFlower-Patches/0044-Search-generics-when-finding-where-to-inject-local-c.patch +++ b/FernFlower-Patches/0044-Search-generics-when-finding-where-to-inject-local-c.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Search generics when finding where to inject local classes. diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 5a52b4d9b2c4810cceeb7df3e2271a3dd6ddbe7f..52aabbb2d9c79a35555fe953b9d27253321b1f29 100644 +index 1518aae1cf006454e11471b52c54267991b65596..fe68098cb9bc2ecfb002438a7b1ed9748d957497 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -25,6 +25,7 @@ import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; @@ -16,7 +16,7 @@ index 5a52b4d9b2c4810cceeb7df3e2271a3dd6ddbe7f..52aabbb2d9c79a35555fe953b9d27253 import org.jetbrains.java.decompiler.util.DotExporter; import org.jetbrains.java.decompiler.util.InterpreterUtil; -@@ -925,9 +926,15 @@ public class NestedClassProcessor { +@@ -924,9 +925,15 @@ public class NestedClassProcessor { case Exprent.EXPRENT_VAR -> { VarExprent varExpr = (VarExprent)expr; if (varExpr.isDefinition()) { @@ -36,7 +36,7 @@ index 5a52b4d9b2c4810cceeb7df3e2271a3dd6ddbe7f..52aabbb2d9c79a35555fe953b9d27253 } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index 135c633ac8ed35d6ccb4d24131395ec6d94ea566..f670f30e2f5c8e2f619d22efc4b61842692b3f11 100644 +index 8807a1534a587af70c2779f2bf8f7cdf3ec9d7f2..0dd8768a10a4edb5901d3112145df58c871b68c9 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -151,7 +151,8 @@ public class VarExprent extends Exprent { diff --git a/FernFlower-Patches/0045-Reduce-allocations-in-getAllExprents.patch b/FernFlower-Patches/0045-Reduce-allocations-in-getAllExprents.patch index dd16b52..5657a2e 100644 --- a/FernFlower-Patches/0045-Reduce-allocations-in-getAllExprents.patch +++ b/FernFlower-Patches/0045-Reduce-allocations-in-getAllExprents.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Reduce allocations in getAllExprents diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java -index 982b660190ba9488c3ff62022aca0dfecbefab48..8dcde8a4d88fa068b6c2b25e00c4de1eae7253a3 100644 +index 4beaf1ee874de373d956177ece541f0ecce64dc4..7bd39cb6416fa4703bab38a04b3922d2823fe3e5 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java @@ -26,6 +26,13 @@ public class AnnotationExprent extends Exprent { @@ -23,7 +23,7 @@ index 982b660190ba9488c3ff62022aca0dfecbefab48..8dcde8a4d88fa068b6c2b25e00c4de1e public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buffer = new TextBuffer(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java -index b03bcfc45ba7d58bcfc92612460c7f3de4bab1e4..dfc36a0e0aebabd0af296ccbc385d591e5c41993 100644 +index e14e8821ea5e7642ff49b04eb4cf1e4d0aa32190..6fcc4845d6912512f52026c13a7b77d9437ce6f3 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java @@ -64,8 +64,7 @@ public class ArrayExprent extends Exprent { @@ -54,7 +54,7 @@ index 097c10a32ed819368c48efa51866420c01584395..34d99a13692ca6a7cedc59b7d4d9de4e public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buffer = new TextBuffer(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -index c713a4055dfc5aa05143a6cd856c5bd98e05c8c1..a67a38179233f983107222a963a3c7664725c9ba 100644 +index ed470ffbbf57c7aea4e82174a99c8d31a097bc32..3adb833472bca27bb0d2084a1ad09061d56012fe 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java @@ -74,8 +74,7 @@ public class AssignmentExprent extends Exprent { @@ -68,7 +68,7 @@ index c713a4055dfc5aa05143a6cd856c5bd98e05c8c1..a67a38179233f983107222a963a3c766 lst.add(right); return lst; diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index 6526b901bc08d5b3a21f0ee3ea31661d86d23799..8cac6350d5053b9f0b66030ca848cd9675106ba8 100644 +index df602b646b7ab2b6f13c42617634f334f828cc0e..c9d1cab8dedad63498cd003ba6aece1308b2719b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java @@ -199,8 +199,8 @@ public class ConstExprent extends Exprent { @@ -83,7 +83,7 @@ index 6526b901bc08d5b3a21f0ee3ea31661d86d23799..8cac6350d5053b9f0b66030ca848cd96 @Override diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -index db2a53744ffeb8b0bdc7b045a822be2df1695b4e..fe9839a9301333360873df16757eab29ce6002de 100644 +index 9b9a0b4198688968201783fb804130a3312aa522..dcc98dfa3fe511a5028ed756717373f9e9e46b90 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java @@ -16,7 +16,6 @@ import org.jetbrains.java.decompiler.struct.match.MatchEngine; @@ -104,7 +104,7 @@ index db2a53744ffeb8b0bdc7b045a822be2df1695b4e..fe9839a9301333360873df16757eab29 if (value != null) { lst.add(value); } -@@ -158,7 +156,7 @@ public class ExitExprent extends Exprent { +@@ -157,7 +155,7 @@ public class ExitExprent extends Exprent { measureBytecode(values); } @@ -169,7 +169,7 @@ index 0509360d7637650341acca72e72e49026dc535a7..1a21f128c31aff9338e3be8cf5d8c603 throw new RuntimeException("not implemented"); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -index e6e3e9d6f50239c716d285d64f37679bbf0ff553..e02bb03f2517be75a947175b212c39883d29cd65 100644 +index 34ee7377dfef29d73f4cd0e5bf53944befafbd7d..926a3d1bd1baa27879b29c7482e69acdcad042f4 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -21,7 +21,6 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue; @@ -191,7 +191,7 @@ index e6e3e9d6f50239c716d285d64f37679bbf0ff553..e02bb03f2517be75a947175b212c3988 lst.add(instance); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index c2136584b0ae2a5c7ba34370666bd8b5f4276aaa..2e020987da5a8d9013d12727427d56e369e00549 100644 +index e74a3c65c126f3378a4551bc96dd82aff9dc4601..54a1becbeb480e2f021d6db8236fe8d36da745b3 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -427,8 +427,9 @@ public class FunctionExprent extends Exprent { @@ -207,7 +207,7 @@ index c2136584b0ae2a5c7ba34370666bd8b5f4276aaa..2e020987da5a8d9013d12727427d56e3 @Override diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java -index 18d2c40d9af0e822004f4baaa3c6b567914a7545..de3723ed7b731fc76afe15482d4caff83de29571 100644 +index 7c9ee0a57cd291ae20b466d70f57a8f11bf4abaa..9644863730e5cda55fa3b2556c90903c578d7408 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java @@ -8,7 +8,6 @@ import org.jetbrains.java.decompiler.struct.gen.VarType; @@ -229,7 +229,7 @@ index 18d2c40d9af0e822004f4baaa3c6b567914a7545..de3723ed7b731fc76afe15482d4caff8 return lst; } 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 fd4fb8c060432591710e25e2941d99c538b547b6..20a42e0a68dc8974fd4fc8bd3b50deddd66d307d 100644 +index 1a3bd9c6b051447ef2aca98b58ff70b3b89da52c..7f4127e65c89b2f63c94cc6a58a96ec9d2f701f0 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -523,8 +523,7 @@ public class InvocationExprent extends Exprent { @@ -243,7 +243,7 @@ index fd4fb8c060432591710e25e2941d99c538b547b6..20a42e0a68dc8974fd4fc8bd3b50dedd lst.add(instance); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java -index 3ad223c61453159d096405bb73184644595b75a9..525a931a299f8d4ac1765160c9267a207a557894 100644 +index cd465813bc3e9076d3bbafd1c7b10c9bed0a1407..29b2c217335ce379e779f80427287de5b33d61ba 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java @@ -6,7 +6,6 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; @@ -265,7 +265,7 @@ index 3ad223c61453159d096405bb73184644595b75a9..525a931a299f8d4ac1765160c9267a20 return lst; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -index 8d68274e8cb064cb94365eb36df65772f8bdb54a..9398bd0b6feaaad12cd86c9d5b85c47aa5462c9a 100644 +index 72205fbd81840cda91ca303d15758df4a2e79699..b962f9154d44bf276816bf109e6a236fec0184e1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -270,9 +270,8 @@ public class NewExprent extends Exprent { @@ -280,7 +280,7 @@ index 8d68274e8cb064cb94365eb36df65772f8bdb54a..9398bd0b6feaaad12cd86c9d5b85c47a lst.addAll(lstDims); lst.addAll(lstArrayElements); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java -index 105c4d951f806fffb8d42386933a7629fa61d76c..7699ea8d3139df210e69208c04eb604c26c8db22 100644 +index 11000d30cbdc93e360cb1bc96b53987bc692e3bd..048e49d62e902485ac89643350d750e7eb57995c 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -67,8 +67,7 @@ public class SwitchExprent extends Exprent { @@ -294,7 +294,7 @@ index 105c4d951f806fffb8d42386933a7629fa61d76c..7699ea8d3139df210e69208c04eb604c return lst; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index f670f30e2f5c8e2f619d22efc4b61842692b3f11..8763564ef768721a913c8e96f0cd1f203289602e 100644 +index 0dd8768a10a4edb5901d3112145df58c871b68c9..e79c4571e227ad532760bdbc4ecf52030b31bfb6 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -27,7 +27,6 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode; From 38535fe0c2f52e4f41622272705e78dfea0d0ae4 Mon Sep 17 00:00:00 2001 From: Curle Date: Tue, 20 Oct 2020 22:07:45 +0100 Subject: [PATCH 02/22] Made changes to bring feature parity with FernFlowerLegacy/FernFlower:2.0-SNAPSHOT --- FernFlower | 2 +- ...ew-wrapper-and-deploy-to-Forge-Maven.patch | 1326 +++++ ...eric-parametrs-for-anonymous-classes.patch | 48 + .../0002-Test-Framework-upgrades.patch | 283 - ...izers-for-anon-and-synthetic-classes.patch | 123 - ...ctions-on-field-initalizers-allowing.patch | 116 + ...screpancies-to-produce-stable-output.patch | 1373 ----- ...ixed-this-calls-not-having-arguments.patch | 57 + ...Convert-Exprent.bytecode-to-a-BitMap.patch | 4516 --------------- ...-synthetic-classes-can-have-content-.patch | 27 + ...-lists-to-produce-a-consistant-decom.patch | 81 + ...so-we-can-quickly-iterate-LVT-hackin.patch | 153 + ...e-DotExporter-for-debugging-purposes.patch | 393 -- ...and-LVTT-properly-into-some-structur.patch | 172 + ...pport-for-Enhanced-For-loop-detectio.patch | 4949 ----------------- ...o-an-incoming-LVT-if-they-re-out-of-.patch | 33 + ...of-Generics-system-for-better-output.patch | 3116 ----------- ...10-Fix-tests-for-inner-class-sorting.patch | 486 ++ .../0010-Improvements-to-var-and-var.patch | 327 -- ...e-field-initalizers-would-incorrectl.patch | 62 + .../0011-JAD-Style-variable-naming.patch | 981 ---- .../0012-Fix-primitive-un-boxing-issues.patch | 1035 ---- ...non-classes-are-being-detected-as-me.patch | 26 + .../0013-Add-Minecraft-test-framework.patch | 148 - .../0013-Fixed-last-test-all-tests-pass.patch | 74 + ...pes-are-determined-was-detecting-ano.patch | 197 + ...line-argument-sef-SkipExtraFiles-To-.patch | 48 - ...ructors-with-anon-class-as-last-argu.patch | 71 + ...id-logic-in-ExprUtils.-https-github..patch | 61 - ...ces-printing-floats-with-an-undefine.patch | 93 + ...ance-Generic-Invocations-Temporarily.patch | 268 - ...bles-and-variable-definitions.-Again.patch | 150 + ...-Used-to-specify-a-text-file-with-ad.patch | 92 - ...thetic-classes-allowed-in-parameters.patch | 39 + ...destination-to-be-a-zip-file-if-ther.patch | 163 - ...hange-LVT-indexing-to-VarVersionPair.patch | 142 + ...ile-named-fernflower_abstract_parame.patch | 127 - ...bytecode-to-a-BitMap-as-it-gives-bet.patch | 876 +++ ...-data-from-the-Struct-for-easier-abi.patch | 335 ++ ...er-to-MethodProcessorRunnable-for-th.patch | 179 + ...impler-than-the-complex-one-almost-p.patch | 120 + .../0024-Add-the-test-to-the-harness.patch | 22 + ...and-enclosing-class-when-encounterin.patch | 71 - ...ns-to-the-printout.-Also-fixed-a-fas.patch | 267 + ...the-varversionpair-in-the-oldnames-t.patch | 126 + .../0026-Fix-ambiguous-lambdas.patch | 155 - .../0027-Fix-field-initalizers.patch | 498 -- ...it-seems-that-it-increases-as-the-vi.patch | 148 + ...-without-an-LVT-entry.-They-re-likel.patch | 196 + .../0028-Improve-inferred-generic-types.patch | 1901 ------- ...9-Improve-stack-var-processor-output.patch | 752 --- ...nts-will-now-use-the-correct-variabl.patch | 257 + ...Each-loop-detection-and-re-introduce.patch | 802 +++ ...lly-processor-instruction-comparison.patch | 29 - ...-on-gradlew.-It-s-writeable-on-linux.patch | 16 + ...mbda-syntax-support-isl-0-to-disable.patch | 155 - ...t-to-invocations-of-java-nio-Buffer-.patch | 34 - ...-TryCatch-statements-will-now-use-th.patch | 115 + ...-variables-that-seem-to-come-into-sc.patch | 66 + ...change-to-FieldExprent-getExprentUse.patch | 27 - ...t-It-will-filter-what-classes-are-de.patch | 126 - ...o-VarExprent-and-print-generic-types.patch | 288 + ...-local-variables-incorrectly-merging.patch | 36 - ...ement-retain-all-bytecode-data.-And-.patch | 274 + ...efintionHelper-that-splits-variables.patch | 501 ++ ...ot-rebuild-variable-names-in-lambdas.patch | 20 - ...037-Add-toString-to-MethodDescriptor.patch | 46 - FernFlower-Patches/0037-Lex-s-tests.patch | 279 + .../0038-Fix-inverted-null-test.patch | 25 + .../0038-Make-decomp-threaded.patch | 809 --- .../0039-More-tweaks.-Closer.patch | 608 ++ ...e-tweaks-it-passes-the-TestLVT-tests.patch | 160 + ...m-lex-merges-RHS-and-LHS-of-exprents.patch | 382 ++ ...th-start-and-end-to-avoid-weirdness-.patch | 111 + ...etter-remapping-of-assignment-merges.patch | 131 + .../0044-PPMM-test-for-lex.patch | 67 + ...ange-begin-end-detection.-Less-derpy.patch | 309 + ...PMM-helper-and-expand-PPMM-test-to-i.patch | 247 + .../0047-Prevent-infinite-loops-in-PPMM.patch | 29 + ...in-and-use-alternative-code-for-ppmm.patch | 225 + ...ng-tracking-entirely-and-just-do-a-f.patch | 101 + .../0050-Types-are-merged-properly-now.patch | 167 + ...-does-some-things-better.-But-still-.patch | 143 + ...erging.-It-s-pretty-decent.-But-stil.patch | 52 + ...erging-variables.-Use-top-down-manua.patch | 535 ++ ...onstant-don-t-give-it-a-type.-Cleans.patch | 54 + ...-the-time-we-create-the-exprents.-Th.patch | 157 + .../0056-Some-code-cleanup-damn-cpw.patch | 251 + ...ta-post-merge.-And-fix-injected-var-.patch | 273 + ...-LVT-first-and-fallback-to-other-typ.patch | 77 + .../0059-NPE-protection-in-LVT-loading.patch | 32 + ...intions-in-IfStatement-s-headers-hav.patch | 36 + ...terator-is-being-used-elseware-befor.patch | 125 + ...0062-NPE-Protection-in-EnumProcessor.patch | 27 + ...ed-variables-in-synchronized-headers.patch | 275 + ...-Include-LVT-info-in-VarExprent.copy.patch | 72 + ...etection-and-restore-do-loop-collaps.patch | 110 + ...-to-before-MergeHelper-and-add-more-.patch | 182 + ...tractHelper-to-include-break-edges-t.patch | 90 + ...extracted-ifs-from-being-inlined-aga.patch | 123 + ...source-vars-in-itteration-allows-for.patch | 25 + ...-detection-to-be-before-For-detectio.patch | 273 + ...0071-Propogate-LVTs-to-inner-classes.patch | 316 ++ ...For-loops-would-be-enhanced-to-ForEa.patch | 41 + ...arguments-for-non-static-inner-class.patch | 92 + ...turn-generic-typevar-casting-support.patch | 156 + ...er-option-iec-Include_Entire_Classpa.patch | 95 + ...pe-to-be-subclass-of-VarType-and-con.patch | 1068 ++++ ...ing-for-an-init-exprent-not-to-look-.patch | 301 + ...eClasspath-so-it-doesn-t-dump-out-ra.patch | 41 + ...pe-parsing-of-inner-classes-with-gen.patch | 34 + .../0080-Foo.-Bar-baz-generation.patch | 351 ++ ...anges-to-Exprent.getInferredExprType.patch | 448 ++ ...ion-from-InvocationExprent-s-inferre.patch | 115 + ...-to-the-VarType-added-type-inference.patch | 294 + ...ists-with-multiple-arguments-in-meth.patch | 45 + ...c-info-from-InvocationExprent-correc.patch | 140 + ...ced-for-loops-can-also-have-a-copy-i.patch | 36 + ...e-strict-in-detecting-copy-var-usage.patch | 45 + .../0088-Enhance-switches-on-enums.patch | 310 ++ ...e-inner-class-fields-would-not-be-re.patch | 98 + ...r-and-field-accessors-in-inner-class.patch | 88 + ...cleanup-of-InvocationExprent-changes.patch | 200 + ...ion-test-to-new-settings-no-syntheti.patch | 28 + ...th-trailing-zeros-and-incorrect-type.patch | 59 + ...bel-names-based-on-jvm-instruction-i.patch | 147 + FernFlower-Patches/0095-Version-2.0.patch | 25 + ...Fixed-invalid-reference-to-ASM.-Oops.patch | 34 + ...xed-potential-NPE-in-lvt-propogation.patch | 28 + ...d-nested-inner-generic-type-printing.patch | 25 + .../0099-Fixed-JUint-tests.patch | 109 + ...g-not-propogating-type-data-to-var-d.patch | 55 + ...e-we-might-be-doing-a-bit-more-work-.patch | 26 + ...-that-are-itterated-in-hash-sets-in-.patch | 53 + ...-cases-leaking-variables-incorrectly.patch | 26 + ...ashSet-to-LinkedHashSet-to-stabelize.patch | 207 + .../0105-Bulk-test-for-MC.patch | 256 + .../0106-Add-a-parameter-renamer.patch | 64 + ...lk-decompilation-test-for-all-to-use.patch | 317 ++ FernFlower-Patches/0108-Fix-NPE.patch | 25 + ...areas-on-Java-8.-Notibly-the-exit-ma.patch | 154 + ...ble-declarations-including-those-wit.patch | 135 + .../0111-Renaming-thinger.patch | 846 +++ ...-issues.-Still-outstanding-propogati.patch | 103 + ...gate-renamer-state-to-nested-classes.patch | 191 + ...lement-options-for-the-renamer-stuff.patch | 87 + ...-the-param-renamer-needed-for-sane-p.patch | 67 + ...gger-so-that-it-can-be-used-during-i.patch | 40 + ...-More-fixage-to-the-way-init-happens.patch | 56 + ...the-renamer-after-we-re-done-with-th.patch | 41 + ...esources-after-we-re-done-not-before.patch | 42 + ...-renamer-for-every-single-method-rea.patch | 33 + ...-access-a-bit-ensure-it-s-loaded-for.patch | 110 + ...aibles-when-the-to-target-is-read-fu.patch | 163 + 154 files changed, 21561 insertions(+), 22663 deletions(-) create mode 100644 FernFlower-Patches/0001-Add-Gradlew-wrapper-and-deploy-to-Forge-Maven.patch create mode 100644 FernFlower-Patches/0002-Output-generic-parametrs-for-anonymous-classes.patch delete mode 100644 FernFlower-Patches/0002-Test-Framework-upgrades.patch delete mode 100644 FernFlower-Patches/0003-Fix-initializers-for-anon-and-synthetic-classes.patch create mode 100644 FernFlower-Patches/0003-Loosen-up-restrictions-on-field-initalizers-allowing.patch delete mode 100644 FernFlower-Patches/0004-Fix-output-discrepancies-to-produce-stable-output.patch create mode 100644 FernFlower-Patches/0004-Fixed-this-calls-not-having-arguments.patch delete mode 100644 FernFlower-Patches/0005-Convert-Exprent.bytecode-to-a-BitMap.patch create mode 100644 FernFlower-Patches/0005-NUll-constructor-synthetic-classes-can-have-content-.patch create mode 100644 FernFlower-Patches/0006-Sort-inner-class-lists-to-produce-a-consistant-decom.patch create mode 100644 FernFlower-Patches/0007-Add-an-LVT-test-so-we-can-quickly-iterate-LVT-hackin.patch delete mode 100644 FernFlower-Patches/0007-Reintroduce-DotExporter-for-debugging-purposes.patch create mode 100644 FernFlower-Patches/0008-Capture-the-LVT-and-LVTT-properly-into-some-structur.patch delete mode 100644 FernFlower-Patches/0008-LVT-Fixes-and-Support-for-Enhanced-For-loop-detectio.patch create mode 100644 FernFlower-Patches/0009-Merge-any-LVTT-to-an-incoming-LVT-if-they-re-out-of-.patch delete mode 100644 FernFlower-Patches/0009-Rework-of-Generics-system-for-better-output.patch create mode 100644 FernFlower-Patches/0010-Fix-tests-for-inner-class-sorting.patch delete mode 100644 FernFlower-Patches/0010-Improvements-to-var-and-var.patch create mode 100644 FernFlower-Patches/0011-Fixed-issue-where-field-initalizers-would-incorrectl.patch delete mode 100644 FernFlower-Patches/0011-JAD-Style-variable-naming.patch delete mode 100644 FernFlower-Patches/0012-Fix-primitive-un-boxing-issues.patch create mode 100644 FernFlower-Patches/0012-Some-synthetic-anon-classes-are-being-detected-as-me.patch delete mode 100644 FernFlower-Patches/0013-Add-Minecraft-test-framework.patch create mode 100644 FernFlower-Patches/0013-Fixed-last-test-all-tests-pass.patch create mode 100644 FernFlower-Patches/0014-Fix-how-class-types-are-determined-was-detecting-ano.patch delete mode 100644 FernFlower-Patches/0015-Add-new-command-line-argument-sef-SkipExtraFiles-To-.patch create mode 100644 FernFlower-Patches/0015-Force-hide-constructors-with-anon-class-as-last-argu.patch delete mode 100644 FernFlower-Patches/0016-Bugfix-Fix-invalid-logic-in-ExprUtils.-https-github..patch create mode 100644 FernFlower-Patches/0016-Fix-JVM-differences-printing-floats-with-an-undefine.patch delete mode 100644 FernFlower-Patches/0017-Enhance-Generic-Invocations-Temporarily.patch create mode 100644 FernFlower-Patches/0017-Sort-local-variables-and-variable-definitions.-Again.patch delete mode 100644 FernFlower-Patches/0018-Add-cfg-argument-Used-to-specify-a-text-file-with-ad.patch create mode 100644 FernFlower-Patches/0018-No-Synthetic-classes-allowed-in-parameters.patch delete mode 100644 FernFlower-Patches/0019-Add-support-for-destination-to-be-a-zip-file-if-ther.patch create mode 100644 FernFlower-Patches/0019-Change-LVT-indexing-to-VarVersionPair.patch delete mode 100644 FernFlower-Patches/0020-Add-a-metadata-file-named-fernflower_abstract_parame.patch create mode 100644 FernFlower-Patches/0020-Convert-Exprent.bytecode-to-a-BitMap-as-it-gives-bet.patch create mode 100644 FernFlower-Patches/0021-Seperate-the-LVT-data-from-the-Struct-for-easier-abi.patch create mode 100644 FernFlower-Patches/0022-Aded-debug-printer-to-MethodProcessorRunnable-for-th.patch create mode 100644 FernFlower-Patches/0023-A-scoping-test-simpler-than-the-complex-one-almost-p.patch create mode 100644 FernFlower-Patches/0024-Add-the-test-to-the-harness.patch delete mode 100644 FernFlower-Patches/0025-Prioritize-self-and-enclosing-class-when-encounterin.patch create mode 100644 FernFlower-Patches/0025-Some-modifications-to-the-printout.-Also-fixed-a-fas.patch create mode 100644 FernFlower-Patches/0026-Change-to-track-the-varversionpair-in-the-oldnames-t.patch delete mode 100644 FernFlower-Patches/0026-Fix-ambiguous-lambdas.patch delete mode 100644 FernFlower-Patches/0027-Fix-field-initalizers.patch create mode 100644 FernFlower-Patches/0027-Sort-by-version-it-seems-that-it-increases-as-the-vi.patch create mode 100644 FernFlower-Patches/0028-Ignore-variables-without-an-LVT-entry.-They-re-likel.patch delete mode 100644 FernFlower-Patches/0028-Improve-inferred-generic-types.patch delete mode 100644 FernFlower-Patches/0029-Improve-stack-var-processor-output.patch create mode 100644 FernFlower-Patches/0029-TryCatch-statements-will-now-use-the-correct-variabl.patch create mode 100644 FernFlower-Patches/0030-Add-enhanced-ForEach-loop-detection-and-re-introduce.patch delete mode 100644 FernFlower-Patches/0030-Fix-finally-processor-instruction-comparison.patch create mode 100644 FernFlower-Patches/0031-Fix-permissions-on-gradlew.-It-s-writeable-on-linux.patch delete mode 100644 FernFlower-Patches/0031-Simple-lambda-syntax-support-isl-0-to-disable.patch delete mode 100644 FernFlower-Patches/0032-Add-explicit-cast-to-invocations-of-java-nio-Buffer-.patch create mode 100644 FernFlower-Patches/0032-Partially-revert-TryCatch-statements-will-now-use-th.patch create mode 100644 FernFlower-Patches/0033-Added-a-test-for-variables-that-seem-to-come-into-sc.patch delete mode 100644 FernFlower-Patches/0033-Revert-change-to-FieldExprent-getExprentUse.patch delete mode 100644 FernFlower-Patches/0034-Add-only-argument-It-will-filter-what-classes-are-de.patch create mode 100644 FernFlower-Patches/0034-Hook-in-LVT-to-VarExprent-and-print-generic-types.patch delete mode 100644 FernFlower-Patches/0035-Fix-local-variables-incorrectly-merging.patch create mode 100644 FernFlower-Patches/0035-Make-Loop-Enhancement-retain-all-bytecode-data.-And-.patch create mode 100644 FernFlower-Patches/0036-Add-step-to-VarDefintionHelper-that-splits-variables.patch delete mode 100644 FernFlower-Patches/0036-Do-not-rebuild-variable-names-in-lambdas.patch delete mode 100644 FernFlower-Patches/0037-Add-toString-to-MethodDescriptor.patch create mode 100644 FernFlower-Patches/0037-Lex-s-tests.patch create mode 100644 FernFlower-Patches/0038-Fix-inverted-null-test.patch delete mode 100644 FernFlower-Patches/0038-Make-decomp-threaded.patch create mode 100644 FernFlower-Patches/0039-More-tweaks.-Closer.patch create mode 100644 FernFlower-Patches/0040-More-tweaks-it-passes-the-TestLVT-tests.patch create mode 100644 FernFlower-Patches/0041-Another-fix-from-lex-merges-RHS-and-LHS-of-exprents.patch create mode 100644 FernFlower-Patches/0042-need-to-match-both-start-and-end-to-avoid-weirdness-.patch create mode 100644 FernFlower-Patches/0043-Better-remapping-of-assignment-merges.patch create mode 100644 FernFlower-Patches/0044-PPMM-test-for-lex.patch create mode 100644 FernFlower-Patches/0045-Change-begin-end-detection.-Less-derpy.patch create mode 100644 FernFlower-Patches/0046-Fixup-NPE-from-PPMM-helper-and-expand-PPMM-test-to-i.patch create mode 100644 FernFlower-Patches/0047-Prevent-infinite-loops-in-PPMM.patch create mode 100644 FernFlower-Patches/0048-Merge-in-and-use-alternative-code-for-ppmm.patch create mode 100644 FernFlower-Patches/0049-Kill-the-remapping-tracking-entirely-and-just-do-a-f.patch create mode 100644 FernFlower-Patches/0050-Types-are-merged-properly-now.patch create mode 100644 FernFlower-Patches/0051-More-merging.-It-does-some-things-better.-But-still-.patch create mode 100644 FernFlower-Patches/0052-More-tweaks-to-merging.-It-s-pretty-decent.-But-stil.patch create mode 100644 FernFlower-Patches/0053-New-aproach-to-merging-variables.-Use-top-down-manua.patch create mode 100644 FernFlower-Patches/0054-If-it-s-a-null-constant-don-t-give-it-a-type.-Cleans.patch create mode 100644 FernFlower-Patches/0055-Bind-the-LVTs-at-the-time-we-create-the-exprents.-Th.patch create mode 100644 FernFlower-Patches/0056-Some-code-cleanup-damn-cpw.patch create mode 100644 FernFlower-Patches/0057-Propogate-LVT-data-post-merge.-And-fix-injected-var-.patch create mode 100644 FernFlower-Patches/0058-Fix-types-to-use-LVT-first-and-fallback-to-other-typ.patch create mode 100644 FernFlower-Patches/0059-NPE-protection-in-LVT-loading.patch create mode 100644 FernFlower-Patches/0060-Fix-variable-defintions-in-IfStatement-s-headers-hav.patch create mode 100644 FernFlower-Patches/0061-Detect-if-the-itterator-is-being-used-elseware-befor.patch create mode 100644 FernFlower-Patches/0062-NPE-Protection-in-EnumProcessor.patch create mode 100644 FernFlower-Patches/0063-Cleanup-unwanted-variables-in-synchronized-headers.patch create mode 100644 FernFlower-Patches/0064-Include-LVT-info-in-VarExprent.copy.patch create mode 100644 FernFlower-Patches/0065-Remove-dowhile-detection-and-restore-do-loop-collaps.patch create mode 100644 FernFlower-Patches/0066-Move-LoopExtract-to-before-MergeHelper-and-add-more-.patch create mode 100644 FernFlower-Patches/0067-Loosen-up-LoopExtractHelper-to-include-break-edges-t.patch create mode 100644 FernFlower-Patches/0068-Hack-to-prevent-extracted-ifs-from-being-inlined-aga.patch create mode 100644 FernFlower-Patches/0069-Include-ForEach-source-vars-in-itteration-allows-for.patch create mode 100644 FernFlower-Patches/0070-Re-write-ForEach-detection-to-be-before-For-detectio.patch create mode 100644 FernFlower-Patches/0071-Propogate-LVTs-to-inner-classes.patch create mode 100644 FernFlower-Patches/0072-Fix-issue-where-For-loops-would-be-enhanced-to-ForEa.patch create mode 100644 FernFlower-Patches/0073-Fix-constructor-arguments-for-non-static-inner-class.patch create mode 100644 FernFlower-Patches/0074-Return-generic-typevar-casting-support.patch create mode 100644 FernFlower-Patches/0075-Add-new-decompiler-option-iec-Include_Entire_Classpa.patch create mode 100644 FernFlower-Patches/0076-Rework-GenericType-to-be-subclass-of-VarType-and-con.patch create mode 100644 FernFlower-Patches/0077-Fix-up-the-scouting-for-an-init-exprent-not-to-look-.patch create mode 100644 FernFlower-Patches/0078-Fix-IncludeEntireClasspath-so-it-doesn-t-dump-out-ra.patch create mode 100644 FernFlower-Patches/0079-Fixed-generic-type-parsing-of-inner-classes-with-gen.patch create mode 100644 FernFlower-Patches/0080-Foo.-Bar-baz-generation.patch create mode 100644 FernFlower-Patches/0081-concentrated-changes-to-Exprent.getInferredExprType.patch create mode 100644 FernFlower-Patches/0082-passing-information-from-InvocationExprent-s-inferre.patch create mode 100644 FernFlower-Patches/0083-pushed-remapping-to-the-VarType-added-type-inference.patch create mode 100644 FernFlower-Patches/0084-handle-generic-lists-with-multiple-arguments-in-meth.patch create mode 100644 FernFlower-Patches/0085-using-the-generic-info-from-InvocationExprent-correc.patch create mode 100644 FernFlower-Patches/0086-Itterator-enchanced-for-loops-can-also-have-a-copy-i.patch create mode 100644 FernFlower-Patches/0087-Be-a-bit-more-strict-in-detecting-copy-var-usage.patch create mode 100644 FernFlower-Patches/0088-Enhance-switches-on-enums.patch create mode 100644 FernFlower-Patches/0089-Fixed-issue-where-inner-class-fields-would-not-be-re.patch create mode 100644 FernFlower-Patches/0090-Added-support-for-and-field-accessors-in-inner-class.patch create mode 100644 FernFlower-Patches/0091-cleanup-of-InvocationExprent-changes.patch create mode 100644 FernFlower-Patches/0092-Tweak-decompilation-test-to-new-settings-no-syntheti.patch create mode 100644 FernFlower-Patches/0093-Fix-constants-with-trailing-zeros-and-incorrect-type.patch create mode 100644 FernFlower-Patches/0094-Deterministic-label-names-based-on-jvm-instruction-i.patch create mode 100644 FernFlower-Patches/0095-Version-2.0.patch create mode 100644 FernFlower-Patches/0096-Fixed-invalid-reference-to-ASM.-Oops.patch create mode 100644 FernFlower-Patches/0097-Fixed-potential-NPE-in-lvt-propogation.patch create mode 100644 FernFlower-Patches/0098-Fixed-nested-inner-generic-type-printing.patch create mode 100644 FernFlower-Patches/0099-Fixed-JUint-tests.patch create mode 100644 FernFlower-Patches/0100-Fixed-var-merging-not-propogating-type-data-to-var-d.patch create mode 100644 FernFlower-Patches/0101-Snapshots-because-we-might-be-doing-a-bit-more-work-.patch create mode 100644 FernFlower-Patches/0102-Sort-some-blocks-that-are-itterated-in-hash-sets-in-.patch create mode 100644 FernFlower-Patches/0103-Fixed-switch-cases-leaking-variables-incorrectly.patch create mode 100644 FernFlower-Patches/0104-More-move-from-HashSet-to-LinkedHashSet-to-stabelize.patch create mode 100644 FernFlower-Patches/0105-Bulk-test-for-MC.patch create mode 100644 FernFlower-Patches/0106-Add-a-parameter-renamer.patch create mode 100644 FernFlower-Patches/0107-Bulk-decompilation-test-for-all-to-use.patch create mode 100644 FernFlower-Patches/0108-Fix-NPE.patch create mode 100644 FernFlower-Patches/0109-Stabelize-a-few-areas-on-Java-8.-Notibly-the-exit-ma.patch create mode 100644 FernFlower-Patches/0110-Gather-all-variable-declarations-including-those-wit.patch create mode 100644 FernFlower-Patches/0111-Renaming-thinger.patch create mode 100644 FernFlower-Patches/0112-Fix-up-some-name-issues.-Still-outstanding-propogati.patch create mode 100644 FernFlower-Patches/0113-Propogate-renamer-state-to-nested-classes.patch create mode 100644 FernFlower-Patches/0114-Properly-implement-options-for-the-renamer-stuff.patch create mode 100644 FernFlower-Patches/0115-Add-the-index-to-the-param-renamer-needed-for-sane-p.patch create mode 100644 FernFlower-Patches/0116-Early-set-the-logger-so-that-it-can-be-used-during-i.patch create mode 100644 FernFlower-Patches/0117-More-fixage-to-the-way-init-happens.patch create mode 100644 FernFlower-Patches/0118-Try-and-release-the-renamer-after-we-re-done-with-th.patch create mode 100644 FernFlower-Patches/0119-Try-to-release-resources-after-we-re-done-not-before.patch create mode 100644 FernFlower-Patches/0120-Don-t-allocate-a-renamer-for-every-single-method-rea.patch create mode 100644 FernFlower-Patches/0121-Clean-up-renamer-access-a-bit-ensure-it-s-loaded-for.patch create mode 100644 FernFlower-Patches/0122-Do-not-merge-varaibles-when-the-to-target-is-read-fu.patch diff --git a/FernFlower b/FernFlower index 4961b5b..6a802a6 160000 --- a/FernFlower +++ b/FernFlower @@ -1 +1 @@ -Subproject commit 4961b5bb7f9e06c4dd15e5e3def5a25773e895a1 +Subproject commit 6a802a6fc971f37b1cde2db35c97d9984c877626 diff --git a/FernFlower-Patches/0001-Add-Gradlew-wrapper-and-deploy-to-Forge-Maven.patch b/FernFlower-Patches/0001-Add-Gradlew-wrapper-and-deploy-to-Forge-Maven.patch new file mode 100644 index 0000000..cf55f70 --- /dev/null +++ b/FernFlower-Patches/0001-Add-Gradlew-wrapper-and-deploy-to-Forge-Maven.patch @@ -0,0 +1,1326 @@ +From e8661f9befc8ce9b4422eb13de5bc2ffd370f1ed Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sat, 1 Aug 2015 11:35:52 -0700 +Subject: [PATCH 001/122] Add Gradlew wrapper and deploy to Forge Maven. + +--- + .gitignore | 19 +++ + build.gradle | 90 +++++++++++++ + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 51018 bytes + gradle/wrapper/gradle-wrapper.properties | 6 + + gradlew | 164 +++++++++++++++++++++++ + gradlew.bat | 90 +++++++++++++ + settings.gradle | 1 + + 7 files changed, 370 insertions(+) + create mode 100644 .gitignore + create mode 100644 build.gradle + create mode 100644 gradle/wrapper/gradle-wrapper.jar + create mode 100644 gradle/wrapper/gradle-wrapper.properties + create mode 100644 gradlew + create mode 100644 gradlew.bat + create mode 100644 settings.gradle + +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..f7284b5 +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1,19 @@ ++#eclipse ++.settings ++.classpath ++.project ++bin ++ ++#idea ++.idea ++*.iws ++*.iml ++out ++ ++#gradle ++.gradle ++build ++ ++#other ++repo ++ +diff --git a/build.gradle b/build.gradle +new file mode 100644 +index 0000000..4ba85ee +--- /dev/null ++++ b/build.gradle +@@ -0,0 +1,90 @@ ++apply plugin: 'eclipse' ++apply plugin: 'idea' ++apply plugin: 'maven' ++apply plugin: 'java' ++ ++version = "1.0" ++group = "net.minecraftforge" //not sure if we shoulkd publish under this name, but it's our fork so meh ++archivesBaseName = "fernflower" ++ ++sourceCompatibility = '1.6' ++targetCompatibility = '1.6' ++ ++sourceSets { ++ main.java.srcDirs = ['src'] ++ test.java.srcDirs = ['test'] ++} ++ ++repositories { ++ mavenCentral() ++} ++ ++configurations { ++ deployerJars ++} ++ ++dependencies { ++ testCompile "junit:junit:4.12" ++ testCompile 'org.hamcrest:hamcrest-core:1.3' ++ testCompile 'org.hamcrest:hamcrest-library:1.3' ++ ++ // maven deployment ++ deployerJars "org.apache.maven.wagon:wagon-ssh:2.2" ++} ++ ++compileJava.options.encoding = "utf-8" ++compileJava.options.deprecation = true ++ ++jar.manifest { ++ attributes "Main-Class" : "org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler" ++} ++ ++uploadArchives { ++ repositories { ++ add getProject().repositories.mavenLocal() ++ } ++ repositories.mavenDeployer { ++ configuration = configurations.deployerJars ++ ++ if (project.hasProperty("filesmaven")) { ++ logger.info('Publishing to files server') ++ repository(url: project.filesmaven.url) { ++ authentication(userName: project.filesmaven.username, privateKey: project.filesmaven.key) ++ } ++ } else { ++ logger.info('Publishing to repo folder') ++ repository(url: 'file://localhost/' + project.file('repo').getAbsolutePath()) ++ } ++ ++ pom { ++ groupId = project.group ++ version = project.version ++ artifactId = project.archivesBaseName ++ project { ++ name project.archivesBaseName ++ packaging 'jar' ++ description 'Fernflower from https://github.com/JetBrains/intellij-community as standalone library' ++ url 'https://github.com/MinecraftForge/FernFlower' ++ ++ scm { ++ url 'https://github.com/MinecraftForge/FernFlower' ++ connection 'scm:git:git://github.com/MinecraftForge/FernFlower.git' ++ developerConnection 'scm:git:git@github.com:MinecraftForge/FernFlower.git' ++ } ++ ++ issueManagement { ++ system 'github' ++ url 'https://github.com/MinecraftForge/FernFlower/issues' ++ } ++ ++ licenses { ++ license { ++ name 'Apache License 2.0' ++ url 'http://www.apache.org/licenses/LICENSE-2.0' ++ distribution 'repo' ++ } ++ } ++ } ++ } ++ } ++} +diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar +new file mode 100644 +index 0000000000000000000000000000000000000000..c97a8bdb9088d370da7e88784a7a093b971aa23a +GIT binary patch +literal 51018 +zcmagFbChSz(k5C}UABH@+qP}H%eL+6vTawFZQHiHY}>BeGv~~A=l$l)y}5Som4C!u +znHei0^2sM+D@gwUg$4qGgao=#br%Kt+d%%u>u-bl+hs*n1ZgGZ#OQwjDf~mwOBOy} +z@UMW{-;Vmf3(5-0Ns5UotI)}c-OEl+$Vk)D&B002QcX|JG$=7FGVdJTP124^PRUMD +zOVR*CpM@Bw929C&wxW|39~2sn_BUajVxD5&Io>(~|Fy9gm>3ur-vVWO-L648qRuK~#rxo+Dno +zN$;BHeJBFq{$312A@64P)Cr$5QiJxUsyQ{(bEyq5gJ$No=5CfVip&aH46>kLmk4Td +zXj+eR5gq9fKfj77AR$KvvG!=REopfPZmgAl3g31WCOgP`{y1k$L|*R_{GeGPSRpYC +zaQx8d0XP?0T%Z4@oRQ7OkHnCA~wEL?pXA2Xjzaw`KK^JFp +z6I*8sBLinU$A2lINZG~?SrE||jUsepZm&$gDtT?$Q{^ziZcZNyYIraxjckc51i=&r +zo5QJ#*ef#0uSn0jAe_G!-y{pH98{9=mhWP6nt5ijp}~va*Y^`XFKUEro+7PQfuS~~ +zUl!$jRl1 +za6yh{VIy&i +z+Ka0B?$#wFemv78?abqT08h7K{b5vSw#P?s4h;pzW4!p^^LJ@j!@FmJ1Um}Wd%JKojYOknfl_H3>Hesd! +z{3~Odlw$N@58>CeT$W*<+}bdulAir8=ut_T<2CvCq4*)>eOH?}`yuvtM_7miv0p<8Y!>RnQy{-T4ME}|DB>$Il{mZIE +zqx=547Hr7(jkqWbR~4$g$Lq*L&|x +zd?2(FuMl#r|KL +zj#k!^#}Y*S5{uVaepITYXll090@eDXd8xWEI8h$10!aWRZyXF&P1j-k)A~cbi^S4$ +zeuVEqoRxP#iF!1!W2|k;t=s8na`Kv=-xoxqzdS&3a?Cw{hcZVpj1p2`S4{gQ98s*6 +zV7DzG4yX&!Q&CLGT((~tN*Xp%>+R`HkV`7vyEmJ!=2_IOShtftYWPrLw~}xNM_0e +zRS^b3Z9b2B$*=9$yt@&Hre9*Y2b?}h{6a?>O6c9WLc6{B!fxqFK>pr7o8xk89_9Yu)N<3ozvWjp3h +zPmt{pchc%36=FVB%|NpiUe62UAds^kig7jKwKz<(`KIWJ`xzEtkpLLNu;@?R6!$~j +zXa67|Oy>|zNJO2JV4nX0gRZZq6-P0qPt6enL86NPi;{-~x1R;CDN$b2_C-sE> +z>NCJISRlR>ygMi`HI7TT{{{SK+Db5y2rQ9Wm@90oB3o0btqU?)v@dh#63Dz%^=BeNIf>g+{Sk?83{-0)wv!}B@1O^23_7@#6|7SB5 +zbvLqhak6kV5woy15i~L~adMJ1ur)9<`FGq;R+F|zF~Rw^$sn_6w;>cDRImmLZd3@M +zKwAh%Sv54*%!4Ze1GJ2>>9lV~XUa_7z +zej{;5F-?hJrJPdeh%5*!PgVnWQGH=%j@T;E$Y@Os)AiCQNY)r{bgauNGIn8Qv!#6P +zv>aNaH-0b_#8&2J(Xp8@UKIK*&6t#BiBu}@0ExVoZ;O+GiQ-6mRb_7FNn?bSo^MhX +zf-6nYPRG;CG8y^yvg5&Ow2+odsO6eDg%OLCXlp7)ve=dY4rdku7*Kc&*!MSx3X>_j +z-(_TmF$kMY0-0L;Mj(I!-ko8sA6AO01SG9jl(Zo_vfODRxZJd*D_9smUMGwEQgH0;Q$Y$lY~VT5i>Qt!6uU!hDOcLMy4XB<(dr_ +zui*M9iaRE}emTsJTIB#9ekn})-h^6*TVq^GOHZ{XV^sYK3d5+&I`x^TQ4I7T3cAs> +z-bmk0l6{j-B7+4f(bS!~VH54a3SaGnTP)qw_+Dk-PQraznR>me*DFdaL+|5y!rx4n +zF;0Ux5s)}`4i7{r<;EdP*2da%)`ror>1xK+ZNyhuqSnkzBF_%xU6(?>Be8BKouSX4 +zF9O4%qwlxzQL*u6IjNMvLB;PG4)6neISC4A0M?rEvL`6f2YCz2e7MNa8ToiylcdSV +zxsXFVuG||t<8Z3>q%M^L6#>So=FbPQx%F0O>7%77nVlL4ikNlYEO6`zJubx-V*ScKH>)+DEz=cD8S{oa)F +z3MqfFWx8}9@B<$B4-N5`ALEF_t`|VtB3nF=L?mR{$8i|0;zEY!?DjSXHourmHmtBp +z2w830pyiD=Rg-ialH9m0b*tA~ZNl!&UaGHTK7<@%!!vVw>aW*9FDP&eJr +zUVf(nk1_wa?!BT+n(1X{fa8z#r&I|F&@NWsglp>v-=I{5KAA6{!^zsMG%(8Vi0;}Uq%5%*FC1{M#2_B=gh7R^1%b#k{Z{FB&!gWF30~q9QoMDiVjgakbIw4lS5aDU- +zlDRYMa?01gXk6DZs+~j-lOpCU3gdt*E8Qm +z^Jp1+5A5V0dynkoKKK;QDRo2uY4i@vd1?rNU=-GiO&FG%R?8{*@j$~_Vmj^~_QHlo +zUKPdELl}cL+=n5K?MK5f*19F-JXQ)Y)vi9TpSIYE$nRn4PFw~Z5IR(L(CF6%qBQHqs +zQTpQ;6E8Otf>uoqB8A)*e}hn_0B7~7R*q5g?X=TNdyAU0l)%>>ydhZhp0?}ylVZcCOF!V0L@fg!Dkse%^B+#Zc`jR)#(CjQd56Zgr1GThOH-VvVuxy +z>9-cOCGK^^HIf;i(uZHS5?Ky!FSC#)i>L9^V74i@!#R>VU)4s54lu6J2iIkOdBu)R +z9(pNuesI`#9s+%@K)}Gi#rnDU8yX8$g+fU=pA3P@zv=sfh2zi=1tOcd16vUAEe-aq +z52e(IDMrba=0STqG?6*<=@uh>8Swmhpya(D-T?fq9N7h7{p(N9*DTCO_&4^fwO(8 +zgkgh$){ug>;esT1#xSgpm;{<2j#`ijhk|&}f@(tqKk*KbEb(T5D9H%if(V!p>S;mS +zsKMhs;z~;YWCJTn2`s0HeZ&0IR26-2Ee`);Y|Os^hT%U0nE!r(l`ydVOBMVZy+o^> +zJE5qee%oXk54cVgC`d^KLxNbmh5Z6pLsQL46(Nu)&;+#0+9d`Xvs<$@0sy%$VxRr6 +zF$3y+oPh%vz0;#^-xQB-?7ycX*GxUHx{h6DUbCHMF1EivUeSMjzWf}Ziz;;&7Df?c +z$r>z;U}t?Hy-xxM7~L_@xuH;zsb;C&ri7?PfjWp)LrG3cIm!jblo3o@xnnQPUkJf$ +z^$nqE_je?8lGAgO7hPL1Fc3>B4bTLskUGE +zA&d*iD8Uy|_S0C*n2u}17lrZZOgPFp6EeA(Z1>QfBi7^qY0hD5vB4u;;#3qlnz}SM +z(WgeE`<)CTzxi4U*F9*qk{~T=)mmmI*FUYMgEHJ~hNdE&9nLhZretik2j=K3RYB*F +z#1#Z8MckH$(6*8ytik?G^b_Lbq38)j#~IC{Kkor`6i&B=m;+Kn=BApI5sQ_(WDEU2 +zU9UDT!jd$0K6507^*PFf)HH0HQpeIKh)$KZjJxynrGo<%)j2|}q}LzY4xLRFjaAGl +z^NK3#MuSX{ERkj%0l#dj5Nm)ana42c?3%Dl9NS4Er0>fE=#FyGT=L%5etXuQaf+YX +z>-5X~4AHVbF>-%2to~DyQVS!el(ci^DJK0Wt&H0tc*0(_;WR&5;*lCb&Bdg@U~LhU +z8W3aFnDAhJS{uLMp!&A8kynE1Tn*}5tlws;rUJ=r*}$d7z}!$j=8C`_a~X8J&<|~9 +zZIn`fBjqyS6m=K|58)xHjSHro2s}l-nx+@BYv@wt@2{vt6l()xQ3 +z1vfX~r+3JV3r;UORrjKUvSWAu3RU;qEp7M0Ew8VFgY-!3i=?3QB|^IY;!_Vu7qT=w +zdc(#k4jsBi)>?Jk4{@>@{q=~_J635pKPIE&B4*4O(amlNp9bfZx^amStA`1C7uL@_ +zt5gl^bcrq^)_gdk(w!_>?x#*~8Ql-u8TUZ%Qc3R2`GtIzYVD?zT%JmBI(j)*@i1*Pf}@*w_7afP#$~ui{%Tt>mc8f#=1#cuZvZorz8lltv*K-MQAdw +zc^9kZN^GW(L1{p;!m|c9lBVwnAbpBGa8OV2%m>G9H#v4SQ +zk|$69J9+JVoei}vo{kMLxBQHlncHaN5%d(kMbykE78)R^H~NgRj=IqY)dmxPcn$L! +zc|v3Ou1|nUk$(>V6a>;ul!L7zY>C8umET2P_#{=8t>PVJ&pf^T{;W9T!-5j;b7BVa +z={~0=%<-2#P#_Xa6XHIFFK$J_MjR$P3k}<#lX^yq!2_9}c|`QI0ElK~-5+QZm9L!M +zlJPg&I&5qX3vLWax5`gJa9sFvLA)9)%1!WXp^2kk8g6Wgk<&ikFPxL{;^mqA>IOIG +z?L{thfTmxFln;=Tud#>QW8cCvix+wU2y^uBY41HRD|Slx)g;4c%zI{c80p5xI=S_) +z!+k^iGh|LXo<{&6fPie_fq=;VbI4RMa5fioax$?o{I5WntoCYzt&a4yybSP2<~HJKCZo6X +zk=@8mHbyu0$n%X)p96Ua{@{%;rw4gN2Q++?Mx>_0sJ-^O21Q$l36+9VaoKvH=#+!A +zcwfA9;-@h2z&*3_K;nJshh|pH*^MG! +zu_hVW%ozAW*LF0!cbN7LX8ijy&*q$4Gcm7CiX>}U=NY%2sudJF$<_mFhYkRk%haMv +zDM51{=UW`wNQ2R +z$7BM2q!FjS{6kOvRmP^=2< +z{s>jh04u=BU2{koV_$U3_UDlNO+*A3&7IUrJ_ZHmP^WFhOWDZ>EWeppJ(VwE1WeIDk1C^o$U+*ZhK)p=Yp5)i0yrZ&X)q=Sg~7i +zfM0*EYUREvz^_ja(C99na!SXokLp-lfe!j;m2VGR1G85j5a^PYmsi!!{gX+@=;!v6 +z*?XQU)lp*cAz7-#MxjA<(ng_tHea2Nff&Wcz_!Z9NJvDFwAfW-$I%*i*&bY{q$6l{ +zEPBJB=}Id51qEK|ODO6I$d{xoH1jm6WLM!XiS!Xnu}h?Wf?cX1SjpC|ENQ!n8!aos +za$_rStUYa6J8F$;&W$-PlDes`;5B#q4scJQPTR7IJz=BU>PnVaN +z+hqvjDU+`->|b)5R7{H6W2&gl{_O0R2-X*FS`Vu( +zP_|oU|DF4{vlkb}pAg*l?IV=5)=#?wW!gSHcb1?R^LjKEq9wyyrU5k_A9QyOp*H^TU_II9b%1ppYE`gRO)b}_CB`j?Wz2(YU7Mob#sm%1nRN&Y8;^p +z0E!yVa{N7vV_0W`!RrQJsq&g2U|2`AAHx3rDpPk9Rs +z&Z{f%G~pz*po0uHuWaAa@`}?f3+YT))R57|UR02=MPAGRk?CMI#O%Z#L%_u!0q^Pn +zvg$>qC$c98b2tYIBR{aI1AyS*NeQ3)hkI?EYhyS!pTqa +zcE7of2o-oFZ&($W{T&cg13S(9w>x;q$={J}o^NI;5|{aw7qrAiz+^jzZllm;x6$7CyjO*{3G~2#=dBje@|%p25mFt_gx+<6n9tLPpO}=EI!QXsa}1-! +z%srCY@SZ=&KO400H0_7(5sQXZdCuoDa|!+FGuI4DqF+z&E|HG1+E)cbdCz%qe;-ds +zsPp2P8tbbVh!rvwn+_)ud|9flHFq`};LR+EV}#~;Xe)a74ECr5Z*%y6r+UaSF(pYN +z3eMmT&e!}l;7vSvRGSid7TM-Crgpz>Pa@s%-eWnV0JUCbw5v!W5` +zkwp-57L2-!|BaXT9rwi#c&j0(Dq#;)k^QEf`j)u=@$+3Te(xLP +zK{&mwoPlx@m=3BI0_6g3-t8ns%b +zRjOGX!h(GT)B?Rmt(8r}OEf@78+`|n&pn!j8qiHC!P}{}>mqoz-vq3SzXJyh57Bpi +zq_j2KB0yb@U?2F98MJO{fd#OIo~K}!UQimY+8~qd=*JbrD#6d&mHX2wx?2Tp2Q#nu +z2YdI@Q6J*rC|huAsN>MdEza(c?sbE>U=#Y<1p4vu`Wg?P$GP54|6;b!Kj&8X2k`*8 +zcn1QmemM?LRrVa0p{8NG(PVSf-~(PUpv#oV!V2oW7ESsTxI3B>k#&a5uo%rmliyr( +z0e2wxV-OoHDp!Q!NzV~*-2F8xa!6NfSc!>)?A +zPz$_;2I_lyqUJ@dDdt^v&cj+s6v@I`e%4TZ9fk<3oMyY}xsTYqX?s&?n)n9ZRT@*V +za*8RosiA!0In%%e;?U4m;_JDL>~$I{OGH4IiA>>v*G2?ma>oHm`zE8WJ&+caVZNc> +z7GJQzYD8brg3Or!5ilMj+;AXpv))SU<3!l6-$YE0m}+V%S>@%#6N*M+-3CJX0=e-< +zlEHRnEKSFO3y1Zc8E(iVyOsZlg4M-Q-XikrDADUk;(Ny65CBaoZ?PTQj{UOq%U}2?3 +zqE3TMOK5!B7*i7HiL`Z;THehb$C7B@qR!MdB*=!2fclgyLxV}t&g$=Z%gQJ>=L;ZQ +zXwO1S=VLM`Uy8_LAAJ`htp2X=W*E^VkD1xOG48lhaUzM}S`w2n6?vxjaDsg_B8LYXsFNW9aEhAc@N&VcRsfwTLYl+u&t2b#jN8@}fiGo;{>G4A$Tsj{)&%h= +z(0Ss~uA_X}T13 +z?vja|;h^r;c*Z}&RkUZ0&r%q%KJ-D=!}=DCl!LwwOb7up^QgnhT!!u&Xpm#Ho7%OR!Qc0 +z>vR_WSiSt_DCFSCesM8zH^?H?fxecN7-<>VY1Q;Jv6+%_9q%ePyDtny!$@vly1b&c#ox66>nD&>4PpA;SOWr)(SfQC>s=p8OP5JxzsysBp%AC +z_p+JBMsBv^&cIXbkl4Fr90?Qm(1_|YK!cXUfMh-dUGZA*u0suuQeh6xv~Y4v*#X64 +ztHEjnJ~{Rt>bIlPq1R7kccDW`JY|mZ`P9PEMLOQxA{@L08}nq!%-wYDO<4JKHFb?c +z${e*C1yolp1&lh&th6G+vg +zr=XzRxYx^-fQ +zFwRl8UXAd?uDUtR2$hPa&%Vl^aM)0y>j=P4Hr(n+AN# +zMUcADA7iPe$j)O^w8jelB#w?;8I8`@Rh*tf0>gyLRrf16=`dIo2T7mgeV>`lu#f*x +zr2Rfk+f|&iIZH#i4#reAzF``M!y;<|w{=H#*T2m8TtE@&^Q{tQLCIq&taw`bx5Xds +zqDhG-lLX!{%efQeFHAv)&DO)WSPqFc=zvE{C}sm72oSj9v*CQtYFiq|9#?{s{82(P-b_zMOn~H-t4c$ +z+E1WK8k60Bs~dooiGjclGq>WKo{Y73#Ucv9Jd|Q$P5kc0wGb)Rj`BRvFd;;#Mu`37 +z74e|UWBIt5T%ubs?eQ8U(Pc%qoqV6e!`8Oa>>~R^Rb=PDfOeBoaF}Sj_=`v4Ie`Z2 +zgZQjU_)~@Wv2&p>PWco*Z{Ig^nT0t0=)Ck?4zLS$F5PK&RL~1Z(JRs@m#e58p+k^w +zBuKfIiCyorn_%lA1MJFVotZ_;V!}F6iL#5sEU@%Qog=6YqZJO +z8=v>7<@oOMwr4v9r0$8ph?0u{4~JmT-2x_4wDfT`ZI56|H5?+ejTH{RC}2a*%djql +z8<7gMC{8E23P+1kRx!g7NilMNH=G1Nno$V&KCEjUSqv%M-xnGx@NKZkQ+ITl +ztGm21{6xE>RT3@aJb>}gLN9g9Dc3DIo1u?4Ls=7}Dj^$Pl(8yZiZ{!Z=BJ)<%_!m= +z-6??Q62JZt?3m^Kiw~%+g76dK)ZnBE+z-EhRQwosfQdIC+a0?|_DNKUL7HV_qh4TZ +zw>h;m

>{cK%Glr0N+^9_g+*qFXo%Qsn_x!QK~{D@R|W(|+L*zMQO}NgP`+hb4Z7 +z)L3A@tfL}tv?v!^nhMXY$=b2epb5wA*ud*bv%RE#&V1M1BUvUTMiA4#_2gmT;;05gs +z=?!#xWzMu+f*<TeXq9${c7>q${D)^J)?$?UfM%gFoim{jeQ=-!4F! +z@@N}m_?$led7Ma9T$2hL&3pk7fqwod>>FSiqKW)+sFW7>SvF;r&$g;sY)JnA<**!!=~wz8kmi +zhD7EIk#)A@q@?#2q^ckn{2Hir6QMjeB(kIToB5%^{+4<59rY9ED924qp8Lg@`uwTo +zq#7CV9wR(NFIYwy{x9l~9XV9=PL}vk!E=uX&nbAGT=0U>qJlWKC_S*a^T>VV +z$(+JUhL07O@V(c7dp!fnEliZffwtJ9x*MS9l57(3rINgVr71+!zp``)_>H@H6KA&F +zzO0^`pP7kk-Bi5}ZBH9#R?;&3PV&k#lk+T*r++RX7Z%L`Nr(dgEsQWP6~kd6K+Zq{ +zt9sdj1|`pKJRIm0>XGRIshdE;&K0(Hw>L%c$*JZbx*pH4Lf3w%CB8$~S0JB#wY5)x +zY;Bb&Kr*iC(ALIHI$$Lmo9Nv^Bu0qt(BStDw-ilOd*uMpIXbn~e>jgs1@4U%gI-2E +zSq0f#IJATJFgbG{?GYdcy&$JwfJT2J7aq4tt?^Y#+oDbcHbaH(bOpo0g+Lv|LvxPf +zgFMj|@B@}>i)&i;HHHO=3ivfe)k^|8x;TJY1vF&yYXH}N$${gPrP8=x2<;6*KQ~lA +z_P%xq>>>A;C=+IB&Q&qGIbJhw%w3}ZJ(tC^;c^W6X_2#L7i2BWh1zc&k+)}o5b;w$ +z?{+3F60gPxGh4O>{z#TU;qQKFJy_V5ybO!@>@9gk539@)@N#+W?l+%b2FQZmOzK*j +zlRdwlOei`eton#x>mLcSfI-4cMXmGniu9aBtn=svfyX|uPgYLZ2@E;+KHHcM`%f^e${zzxB*so(CtD!$)=^V>ho-hCoM&bzYeZvuZtyJ^HNzU +z*Sq&XRow!m5kq^VdQ$l|l4EpxlvN{hT?-a+0VCHDKe+USX{m+C>G!rVv-$ICN^~^L +za}%gVp}M+!K$%~MzrjBZ7zx`rF0CNL|L{9LeKW?BU4+N@-9|Qs^w+vESBGyV>YNYP@B)-|62L{pMV& +zjRV>5mJr<1)483dC%cS3UuW#-fjj;2O;dH*80l*5RVe}?6EJkL!l#&FABrrFB<*ij|#7j +zT4Lx4$VwpI${D}^EP(L*z6k+x7?xoKj%J+Fr*4~MYgk^i$tL+qOILY>Tbh6ACP2N^ +zp`|9kVXks!u_>d>7R}W>`{HZJcavS1UTgfR#!75kkup^&3A{z42YrHIGxW6hgSEUu +zj0>xUc1l9N9eFBh+JY<7`KDAYgQ#(l0ga%8@OTQ=piSFXLm;q1M}<}>mjx~pca6C{ +zV`^B2bw~okULIpIrn+WWO69{oM1h+Kc#55D0%rPBPPGe6YfJeD8-IckVi^{|q +zIfRy~XEtUbA{ywTMPuB)>9kZm=dntj+Ah&XU;sfir8`6msIzt)7qC>BSRed6vMa!R +zHStEoKPCz!5J4~v`3c|+EiH)VOzwGtCAv{A`T(*&%4;@LM=`qlYxaH-r7Gfr(mg^L +zSoV1Decek13Q8QBZ{S$eIGANNc%{iEW)B8TZ;u*m=7#mwaUd3LAXY2{55+^epB=h; +z$W7(q9;kwIV43NnQXjL!KSDAk|CqxDrp +zD?^$s#p$^G<7+g^U$qf=iFNEF*aH&Ut1mTWip<<7(;Hd~ +z_PU#BDya{58YXkfZa=t%Yamzh7TRyVAcU5tN+R_AHS0(>svS%#&SYLxqxZ)}xh&T* +z9Q65qb9+~?M0ssb^rMRGTE_qCj$l&?EKG!K&(WU2HlWa6k|rVQ%D)5G&iQH}+f<<} +zV8&c34i&&#w=8->LfT-YWhy7oAdY2)%n_|V_5QJP^1Y1kbuX|(8$Ep97&%Wfdx6Up +zaua~&a#ApN49Pt!U$BRz4^*=t6N^GvzZd#V#vOh%^*i2Zu_~)S5z#L+?I!AIcWMBg +z-#mYF?IzcUvF%GK8StiQIG6=IH&|n_Le7u+#5Jo0NJmfS>`=u3LRb( +zzGMUnCC@&)@w%U(+7Nd0VQN+wAE*m{(gR%zm`pF2@jzgk(-ZqPbNOFse{y|=0bdyo^VXo6TVtKH(=Mv-6!n!hVF +z3^YpNCIwQb;JL#%ZwZ&IK_IAGz^J=J`q^Jflxs!iV4Jimlp=GW?Ya@w13x<1YYaR~Q +zDj>Z+JKyz8x9K%2`|9Inc3P-Ce-pah@w~Tjiu(8P%n>a#LAb}{JW3t$hr9j34y!Bt$`ou)wB(Z{fhFhqi1j=!5?>J$xW8NXrM +z?UoMd2tK$(>J&b58=vktI9C9@PI={J>SPai9{cdc2Yb~qud~ooVc$s=AE$Wg0WELM +zPtRCIedri;(NVMs1$(J;EOkM-7Veg)2gzD!(>bZseI35=6j+L&TiW66`KBo1`3*yp +z^ccW7UbfUiMwMB!1*|qMaOS+VR*RGzr-XIRdT~Iz%ufxUxDs^0~XTgNGLImRm +ze>0t8iv>Pf{=9JU3{r~lK*FgE0wOqIF7u$>2$flHqF`vOksk;6C1O8h4a8cFQ!|wx +zJb-uaiTd1gH$5vItO71nyZ9RH6i_Iwe!R%3DT!^D0UDfSn_OGC*%_Z@C-4}c!RC`` +zql&Xc+#;Ln%FVe%x&u_ddpb*3a#Nu-D^4~|=Cxdt*2^PUx`men!)eU6lL-s`+MmC{C)CeH2c)`bX9p3FPM1hw~ia7 +zd&l|J0frh4LvkLr#$=Mg_r_t_n9v^dQnPtt-)*J(_d;bG^0 +z?s3nE>^&2`AiNYr@Q`nQ%iQHfnM|8%~Rmm+@ +z=f_V;{0@#(a}9DS+M|D=?(i`KAlvd%NO~S@ZoUuxF=vE#AGi&S0 +zPtj3QYE`cai2UJM_C0MM$={mJ2KH!IuBTGk&4%8h#)leI{`<@^dC#Q83QlE70g|X1 +zjnKrGrm6#*^wO31nn?`iE7)r<9^f507*3xtCpod9>>077C_}|tCM`;r07p$n2|hRLwVNLsB54$bnfe*ddEeNdRpgA+5+C)lLZUKK_GBiNok$`(G&qo*lwZh{J?>0-q83OgH`V^d| +zjW%w^K+gzWk+~9_zCDq5q(NjG@!2>DJV7Ju=yu%q^|fnZC;tDh2}eXEwJCb&1qkPm_nz8;a0fj}$aH;E +zt6?3rV|}L}ME1-nLL+kHL}+Qfg@LP^@U9W}q~S{Y-cS+uFH`K8;!wIF-j2-~t&LA8 +zm8`LbZHWZW`36`}R}9*}EgJD{sYhsz%+G&6>6W%eovt27u3OGTXcpftjm}3tQb04g50EPsSrXbT}>Q|`_CKdmxb +zZIY0yl+`KFq-P8l+i0^k%NLycIZIke%%TcGMkMz{&~A-hsJ*;DNQY=Y^K5p(sE~ZfOl2 +z_BABj)#8lYVg%{*$cui`9qySxAmpNOO5oHIE;ySL=_ea*DnktdfTF0Vj?k2wc^gI9 +zqa2%-qx{&1U!<09>X;wnx4?{MaYHDYOm9l{^Y-?zIpCQ_9uLz}_gR7~+ktT#bW-hW +za`zwEKD}Lm_G7(o;yYSHzK01fkCaRilV%QY>R7AMK$mK!HCy99&nds~VyxSU9def} +z11iEf8mAk+|BOk&pwvAZBn?U3<+>BIczOgSRRIy$o5_XA`Ei~-585Bj7A#w|7JTjv +zK%=9C-3KRMWR>%C0D~Gv*0(TcM6(~!zoW2B3|;4J#+PG&@EY&mwBPEz*%;;CCu=Uy +zn*F8DP}q`k7o9H!E&qr*z9RdPz!F{u1;@3#t#oI)+5yPOE?(6;XC11GQ>NXjQaIeR +z;X}`q#>(W4hOR<>Q|ANwClHP4Pr4!c3q*te0#T~}3`GC+=i0yF=>NEz|5rZS9c2XY +z1u>!P(FIP7Z7o;}VA%OVBO!!rEo5j7VI5>+U3(svQe8Bp7S|ZlxF?ZVtnOLjws2&g +z!Dg}0L1JUVZYwlXD0}_hef`jV-S~YWRZl}ZvVxGdG}-yO{ka7j%l|q{4AdO)NaebN +z2GF|k=Ij)Jr&qZl0vtNF;n1tyAk*uf4OKZlF#+gDs8KtWM4L8hhAR&4DpWhcYgFws +zp>rEPxBy-5T_PPi@NOyzJ8}TGT{!3~wHq<|tN3#}r8+D-HT#+fvW*f$z*hcF71gp- +zQipv{K#Rw%E8zSV9&kO_aZuwnvCHe|UV~oJ=`IkAjxf&Yzg4pL`SL3Q)>L(JH;@Xi +zzcT=V(p_Vy$X#T}!h1C`c9a?aanA^vkIv6m$d-?a9Y0YZ*7H^p>Vc9TPyNQCY=YMD +zB?_H=?AomBB`acP9|pSnWGMAum%ic!x|=GrrtF2Q`}bbvONzkfRs7YK!uD=pfe&%$ +zGwkI#HxG+#CLlA56$b5)E-hsQ_w*S?a +zf}R~-iJ>?PQj;rmQd46Ll)L97Bmy0bD9W%t7oPMTADi6>{#%rwf_zJ(Xp&Gh}jJmAh_?*qEhnp1_UYf4964yk6@L`z_b +z2;oH1zX)D*5mpyB8goO3E0LwmLNq!_8%ZId*y2%4Qj4*GTp8T2k~WDMClcIi(p_6# +zq_BQ~4bGoxz;qA8|G?j72trK0n1+}y%S;t$Hj!Hlb||YZ-#HjYI#a%I2WQMmNwk(F +zzCdp+VmJWiTuC0{oFI79Xt=1N-t?5)AZQ^)vMh6RgRwhJYOUc~WOa1xXN5S?&^Q!J +z6Ajz_Uiw4YS*?SJ1r3oMt?T?a*KN$5>k>))hj6$QLaUn&7AQ4C$ +z>fTl_Y~8}5k9b_vp2*a8Uyk-%3%Bp +zH%=b`2DOOmUJr{8d_H0W^tVAFdb=xFd+sqI=Y5GieRhBkxq<6j2!B;N!A<%K9U8LQ +zHIs%Fo}93B&!E$j3!If3*bNHW=aHe}@obFcs?#f#@vw$gQqs-bgBvsdXu81;4P7NP +z@_F)tlq-sN^pE5|#S?|{^Q;SvQU&BEJLs?KUHq4l5I;%!FRh3t{Ebmh7h0VxYqU~L +z=L5-))HWZ!WVPRrLSdv46bnJ(N!0m5C=oYQ`AR6|rTJac3EC`=Lhez8C~7RW2kew> +zv#5$y;YCU+Gf0-D;U@WF`ev~?5@~7#hO@{H!vX|23(94fSgiJgGT`-l;2J$Y#1l+; +z5KSx67nQ~I_um$WV?-4>Sv<0lnpx_!Ur0tYWfvt~zw)wOGZW>u02$(yh}5S`g3S7f +zp!FpF+EU6v&O}0VF1Ep{D3AGqD86-4J4%MeFv0`|>LCJ_!;s>!BGD2A85}=+Ly6R^ +z_CTTS;B!Do^5%KK?FOLb`; +zANqUd0l<7o)H_o&4##twRFjn)scla?4Fa%-mTNyFCKb>+Ej9mEfRxNT5F2DmH}X_l +zcZ%mLpOPq>`bcilsERe`I(9VW*05D~wd|znOs}F9!&cM^vmUgITd=Fur-J$G94nr} +zC}`ZbYepX36(=;eoABN@p)M%>VPducxE2~%w#~*b=X9JZ1IYH=9S~g07k^pRw7@OM +zzKMwFzM`!^Ou9uz(-vLX_uSFacQe~pl?+8o|7DKd+AitJH`yW#SML;>gl*?`$NNvo +ztG#R=w~iXFCPS!a8>YbOTm7yK@&*q?3saEXuhumzK33x^$kSb715wrwXJ+qP}nNyoNr+wR!v*tYF-PW^kWea_O^&%UUq>Y^?RW6n9o +zH^1?Y>t5$M?yG~b6~j2+5zN9}3!#p@{x;s~5%XHq;F0W_&C+tXbB1+>ULPdh~sg|!Y2NLApamJqM-$@(*kGBMs-r(Dt|$(QJowROIU+BV^ZHe +zo*tL2-R|^&d(6ZW9>Dp?PX06A;!%~6HgX2J4d$fI969X4BJkC-vN_> +z?z|q16?48Lz}&16Tf7qH*`yDv=>WOr0LGS&jtlX-=)FFfzB1AQW&MSu9fp0!aYIT- +zsuRb-dBlJ_TMzzf*UCDfrD8A};(i&4XnS}*k%IV7HG_M<&;#Y4^b#JSCIgh^-%IbO +zd4*vDyKUL2T@q`L;7x=;iRR2~9lg4D`;8RmZ48JhH=XfM86$7uY}+9koEG`z4N{k2 +zQqX7g#T>oKWkV_}{j +z5l*><-BN0{&^Q9w{#ZTR+}TX$8KLzVw()@3KYDQRdNkU*&Fd>({nWG`)3*XgH?emB +zPrc~IU(EN==K9SWIU$=ka@cc;>Adw5y#3_-jynn$*~F&Msm&1Whn!h(yCa%fc7w;_ +zEZcfR0!zYohSBCvZCpXz5KIbUm}G?uW7ESbH8C;V5y+fc0dm+=+QXhei))Oz)R^ROnUJ28qtU}m~uzyV)pCbslXo>lpt;wd5OZ%dx2G-o- +zBA#R5oEDx48Mf)xxw6*1;?wLZLXG&Cm6NmI>U(SS74Zk!=6Z^RU$AH-VLCP+z`kiE(3)!YWV|JuNUb7;m9JQ7oAtE@m9zB +zREE`6@?=!sb5kp)ReS?ofSXTpt;{D)Odydm(^u{c8KnjlolgCJ4rPR94~~S4_&CU6 +zPwH9S3%nc$Y!>tb$HFScr190?6hF1aig!JUDaE=mM0#M(5O@!P(Wy#U7)~+&Ytv0y)T2~m +z({p1XD@mq|b{@9m0=aq8e7vRjG)Rk5QMzcQWm9!LMsnGM6?+?;tq`RpQ(-{z%+x#8 +z`K>w)p1#Z-k-psd&r*eYuqP_)Mo_)x5LcHpgc7^F16C#&noPq*Nk8lUx?%@nVoQYD +zO-01=4VOuIA6LyD%*^sGEUMjJRYYr>N2ba3jt-EWkYFP&>h*3F{B`BaH~hJfc4b6c +z*udx)d)XntP2Ujt%R=akvUd!4Jn}~DOSoXuHg_>OQdOb!G6x!^?=U@YR7G2u6qT<@5}B*Zm^7QcwWF#av=2X0sFBq1Xk4cbfDoIRcve#;R72=+ +zmlSzU@3N%0wcZj^;vEn0rcO(H&3~6k&keO@)C`Z>=y`~2q(!M%M4gKr9kzLKoQ?t! +znHEzZCnHNeAp{BWD`K0|geg8@%%Bv%is(~NL*`&AVj`?DubTN^ +zUFqxG9_Jf&B=v9BlKwc92#}wYPAzPYu~^!Mo1)~cIUb7sdZ#@yuTU!F3Gdo%vA7*` +zqfe0K93)zpJ(dc?J4==ypLl)xUS>D?^Z;(`>4|j$G9~nNUYAqFK3fJ$dZYM@qsbA5 +zsL2wBH2;m!T~K8lBWV`Zoj#!j^jSem(u)7&S*g-=IP&%zR$nfJ^GE_JVaf#nG=c=H +zCwAI5Ym!v7+X?s8N1b*!4Q!F5QnpaU_zvYm7{8D>yn(1(D_!Uf3N1mPenNE=U1+$V +zqu~q3d&rG4b3{ta!A1P%1M*|~jRoyNSI}gs%#g5rR8hhRQKQJ=`!#zERm!5?kRkk; +zPTmhMC+Xq(qD19I;LIedL#h<0D1GAC6v&U5IhifW7uF!XL()CE;0th-Er*RouRpoi +zN;KE5=}B!Zs1uvzrS_DWZ8VmpK_M^OLiwvj#Sc-39im!n!Y7CHV<$>)AF#QZ7A@nQN{n6?n)`fp)4)Hcc`dXut +z*9pNC5G#Gtc>wawNZ6JZIm%a|t_v2`{Rppqu=?3g8b=$Ow-RYngvvov@jHXEBlDrZ +z)#wLz5I6h}@yeY(YlHRU#u6&k&Lgs~1b}4<}kTo65 +zciD^S2d_Hz!gE1(Fd&FH6RVLzn;8%bu*LC4~(D@l2a;E;?5_G`Fm2HF<%pr4S2;M8{PVaP1D-*xa{l0Y#RdP=1S3|(d$vjNr%=mOY +zD3HC_u#Uzm=Q3=cMC1~wYIM~iz4~rcP|Muh8L^gKAh2PjUk&2Yu7yYWS^U11!u3OZ +zz1`9$@R|~~9QMFhuDFX0>OOn8mH0hoeIK{8)X+jg!=g;Z2kRwM{tFTusb6#nX)J$s +z{9wPpDhdhBrgr+N*%Hnvxj1NtK&H5cG@#hS*sY>@oEFJfYbE~mi?lOG(dGW=DuR1N +zixrbxuQA_t?3^SEVU?}zn+P`qf<8|#jw#4X+GD+dyPIF^#jvJ?@LD(@duKy3GL%Z= +z_#F#d)qU>nEuRvG2W;5~&mh4EQ_$zA +zb2v1b&~$~#1(OAM8bX0^Y7%pPqoPcIWPuOqY2>){={4;PW +zSk*!c8{kA06VLb!@J%q(1JbxXkqc5=BQe=5tSICmP$d*`lUA4Sr@#%xm?owN#hIPO +z7W2*$na;%$%WXCtE9JD>LJ7Q|JMf?MpU^hjKOiLZdFb}qovt~bY3_TDbK1Y&W;Wr! +zMeX8qy%7>&3>M&|IKxd~-Equv+k$e}sa&U2{sBA0RYlvaf{*5@K +zf}1;VT>J)&)l;@F)kYRde-6-wumZl=H?i~2Yb{dl974IrS +z?5x~n2HaS@)drqf0OG+pm2cjDsJqZmCY5i|-Uw7)uee5vJsDKVIh2}!-dn|a_+FGz +zYS8{+@Wg6zCHeSPLtU5m(u1{_fV1h-By(fp>BDQd*>Q;+wY(yftMp3Bd3p-F9ol$- +zNJ&MWi}%$+`Pl0H>B6c+1Y9$cb2*gzO6EuzBXVmSKmsHo`RYkzik}rP)+}*XhAw +z2NjIxghxT0+qi3rXeth~8bVb6k)1L%s7@pw*eg-9K^HBBQ?ZYNlM|EII_k?RxXvm(C04IQQAMp=72NyB +z=;k%n=zeGr=9>oFsrH6F7!ia!fQZ>I^ddWQ00p4wJax^9OQ;4_31| +zo4>yBxiD=+hUj6sf?HKS=6Y*ytUv(55Ny`41nMv58@QTA7WQ47=XR8KQB83%qeqqs +zWB=`mU3jWL<~uqcW4#(##GrRPAwIy$AFI83_LIGO4njjRAlJKg;JUrEs)Jz>>)=%C +zDh?yP+YZaUSgNp9QtIA#qI4=6j1`qsYc|*uhB^gnS7C>Z1x_s@)^A-8IQC-jZQbD@ +zSBzi3ei@7t%h$#;L!+zPQEjo`0Pz;>f|wJy%QTgDcwPr`;3&;%#A^LW(rQ@UNw=qg +ztQ~(+0sEfG(pciMmFh09x5jtmmTk3L-NStTtxfsjW24HTz6yA +zQ8K`Tef~6Mq<$^9yEml03H~E +zDZ1J=B#4dC7Gb`EM6JnE6&JLi5>uF^^WuQVv53i>>d;TqTMVqnghH!Mr@ooUC-lJX +zw`&C10MBodjrQ`(?-d$8dx%@wZyv=Mf(V@+oSsql16_@vHwra;OLe|DjH?`+v140f +zW?>y9F%I4d)QMj1I{e4IR7pSk)*)bEHbtS;`Z9Y0OF3MHw!)tnR&<4L80h8SPioLd +zC@(h|M&@7I{A|u11}OhXgTvg6`0BvAMRXR|P@{DO-tY)7=b0v{n7bjAk3_!l;s=L( +zJ~+{F!mN?fJz9=B;-*)&IdUJXStMYL5hi0r7yP#+#8@jgKT!hA1Fe2no9T3VCD+X-0UvKMUc3^TJwpHzBpvHJN +ztaaiI-)Y2ydT}eV7siXTtm!IBwc_>p>$&J^7wTz9=s9ml2=xJOTjVeXCP+$_s| +za`r57kXdR>1VF0rj27<^q|qaesYM=Q58r_@xt4#TGhwIb6j{Z}c}}Nbl%&2sQPK{@ +zJQR^;4mo3X3PEJCgxg21I)&)w3)U#gmjbuks9tW47U`-+=>2N +zXWA2QiFcd?{QFLTCSUy-bm$G`p94&*!ydVJv#LN{-T@8hOC^pOjX2%mTa9VK2bZWN +zG01BMNS&Kq*f^GSu^8uxBZNF#1oP!G>_M@-uYa*KZ42_C$^*_@S-|5jit69`AZh>J +z2TA*1*i?G}Wq{89|AIx8rl;g6rzBLwC1fThCuqhdXZ97Jre>6GCg_zIm=qXT>X;Y- +z$VXLsS6BrGCI*&WDvI$LNf|oI78!a;=`o2#ndz|uDyk{!u}PWcL*RdC&fEY%Z(*k# +zdS?J11Q(DNVgQ~ET`a7PX&p_BOf2l3|KU^c#7@}`62JsqcS$xwAPc&}YkO8IUlyy> +zCKHlPQ1OG3ob9u}&%YhnaWgmQ3~=Wxo0q30Av1b`Olz7znB6>2Q +z8^KsxH*a!l;p5EjK9i4c(a%-^{>Y2Piq-rU&6qmn#1i<(HzjR%A!0W&0x_|FbHL|w& +zClu~qZ;u;&NZ|%>pp*cFK*oQ6yMWZW!qx=9gK`C6V*lHwo2;w@ +zV8WvCfIvr5w}jbLZ_mOX7CNu2=-ibhNd}=jZna+&+vL1oGl!g%zPM1_*a1`B~6|6W0S53|Az? +zedtkJ!zAqJt`tUd^V&XSG35L<(V%upWWv%7Qi9!k{VYebU*#RLY;5MrKY!sS*odqD +z%(>mdO{Z}QPuyU&;p*8lWm&=4W&6jmpreB6O55aP^H=Wm37K%RYNa+Q+a?|{%t-ri +zx{GbP&VMacUU;z5c%ueLVkg^(gi=%atP-7A8lr5fZQtGnWKrDAqrdB8Q8$r|0I7>aTx?2- +zXV4T*S1aTcyo;(5cfLZ$$D)Vjphyy%2P--Rt!zQuUe7~O8w+?qR?YhomnmZ$%TiI= +zWpCB>cFM^G6)3s;hbC1{$3t?kkso7>@MR41mAsH2SOswpHS&9g4ZEToH-R7hzlW+IeR!i?BMtl&dyF0fL%T8yQ#-i=pZFm*b(!1uPv8c$R~ssaDyFDQbT=5I_cBx}9TX_B1)o33V)#=i$0G<~ +zp3w#bTk!d96A2qkRVZ==EZTb1)|W0zz1NEpcN>}qretif72)BCub>0xa6ODUVhAgE +z?^<+VD>N^1M8xE%NLBXjT3zO>m;J;P8V*xGQ0X(Yl_RlhWNateX+s!VE17-~(_<#2 +zm?{y$Hgn2U&^G%vaNiTMwOM*V +zD|#{&)s>7v7PH@KVfrmcotl6-(1Ui*) +za|+Yq&3}kc%|cx^kOYj7laLFO=#tlh(39-$;#185iF9#(g#14TdUJqp;E0A`MJ2XiUlX`u)?OoH^U +zpZ2&Q!R1^@*EVf(cyyQ8Z1!W{$Vron5XR6M@ciw-A%{uR9HUx<_}C9I?D+Siapv1l +z^3b?>_!VMi{`EL+T)NR*+)P1%X>$0n?Y}8HY?iV|Q +zCF+W3%rJ|wf?x`pbC8-Nz9Lf_fZn02_KVChKL}Gj{X_Qf*TK_OCBqaCSOI~6gNNsT +zvjYAW`bq%##?}n5KI{zuM8f|DlV>Z>$RPtn9McXH1DpK2LjC3d&3t)dN&<1ou%d9t +zdPHQH@U4=|5*Q8Fv8$Aq+TO9u?_RgS;bg;&eo41euGNB8mK@Gona@2Q*Xwp$40s5*i;$!IPEiIHI%g(+oeetY@&qEs72V+FO~j4Zh9_jW>_Ag% +z4ZYn8(W>Fl9kO~OyxB6DK`Yab2VGi|(T$d4=h42EED7UDyP+`O?tLhp1vQT*J77&L +zwHg1a!?ho>7!l!vo|mXgi1;D23=J`|^|@80ZPld4(_kr3{-Xfv_IX0hOPDj6uy`2* +zA?5u2bts`DXyfY}X2_Gt0HT0Wc*7%o#T5VA5k6^aNAOCC;&9LUgXI!*xh?DFqOAn3 +zB*9N(V7dAlqrhDcy%>{St^#ul0gdTpRz(r_aX +z)gV-(O5*Xk<{H}AryU}X-bcELN;_N +zAt_Upft6KZSEhkGA@MPVc@x|jYPeiK=8lmY?zS-v+6K?am>C6M5UB8ghahr+U{fDR +zF7EXo{8oR(`Ux@Yofse~l>)^3e@L?aVYdhD>@GF{>OO$TZ1P`Q{ol6u +zxi{v*<`zvG>a+f=S;VDxKq;`gBB+Sjre`zB$rMkbDz>rDuroS%PGv;X&NIVv!f)@8oD)-j3->$z+ +ztds*KDFhh_2It+!sv%zZPW_q?9ye-f6NdKqgf>0op9IC#$$oUsneUvxk`~at_>71l +ztz>gKgj0PiXRMri%P8icFw$X$sbn(SJi+wn?!277MQP8ifKvK4Vp%8!DhW?g;{KFxPwa$ip#Z`?j_+qu;|W~Q!pkfbpQ)uSZt?mTp@b#ZjHOXMUl;Ee?P5iyr{%3#3U7$1Tedenc? +z?@mZNw@UB*>RH9dJ0c9`a{2w6q;3>tltEaeI3YGL2~hf4(wwxGLLS +zXwvy})B`5nJ~t8@e0*{Z$8At4y7j@e66T9l)Ju_XCS{8_JMY +zm>%)o4#1Tw&l#6b=VIE5w6m(etZ^$vo!w%OCbe`mx9uz4F!!X%oS!7qQyYLuMWcJy +zs=6**T(q2Mr>meQa2GFq1Td*2=$lS$bQ=yuct;T+W1;zXw!h#{HL^N3rFIjDZMvH7 +z=lUklbh$iM$9?o64Jq_N0Jo*5>=;=`=Xd6s9Oh6@d1`&IZSnc!pi7gX4eKq>Q;=M0pQ_bMi(D?2 +z8*{jeP1=i#R|_gr%JZ1pf}ak&`_H&sRU@Mf+dC3$*OXv#`%sAp?pXBPS!Fd+rSqsMLP;*Pg;76 +zU+H(Bk^bcE#9jpQ?FzNL^m6PM|3khh&A3L_M|=q#*7{P)dYFqS7~n_ +zDF^Y_t!@Pfb(6ZZTUN%?G@IorkJM5!<~JyJ$KB#PU0f{aF^kjEhZf)%`aeyF(O{80 +zy~;f?4(O*FT`b^CF@|gyQBCo0As_j!Mr38Dyve8=b%;?259WsqX3=Qz-ZUmdWk)v~ +zLg1NOW;Q-TzKRZ`d$+HF3&#E!cPoyxUKQRU@H|3Z% +z2s5uo0$Wq0&&Y~>o%;Ih<4rq^fIbUQIpy$OtDPG)lzLGdwG-SR@#aP`+1FI5IF0Rx +zYNl_${HM3H(gO+5wD22;nd@u2v&81g*&&jB6I|!ywj71siwG$Cm4cs(`}*JKtap7Z +zuJT^5Jp-ibIvWx~QDYl}%+R@BNiOk(DGmHf%=b|w3k<=Fe{%+fn8~vR-lgtvVcE^d{gM2`gAs<)geKN$~ +z5wLa(|6YGsj5pX4${kisPkjEguY`$B8r#Fi6&(>;X8|{EZ)|enQH4bpofFJr52rSn +zcQ-U_Q6-Bnb{7jtXO}gUfdmtu*Idfnx-yD~ASZw%m-tv(uaPB?>Wb=9~`zfP4>rEYy5)WE?D?a{xiX{MRvX>T)=9mF}*aK$X=PIw}`4*BE5?NrnOdY +z*qNmYPG_HfuZEWNd4YKePAlA@T#_Si;sY!NG&We#@nra>f&nE0U9^9CT+nPZpxBB~ +zo1X7w!fN&x-oHrXbKv`3P{6~W)roaWs=CGN{ZLyYml+6kM;va!$%ZoB)w_Zd_iVJ0 +zQg3qHzkeZKE7JVA;_Qmt@XK;^O=~DXdDcg^9TG_R!~@%9)(!azq#7EDzYpwn{*CdX +zu>r0CSs_LXQ7_X#0%zD%U*688tiuN4U@DM?f7^6*d&;CyzJsvXdXuLvZveF?5KK86 +z2&H5ns%8Kat-o;oJ*0G(f%lA5gR^B9qb4{icK#We@DKI{hKUcPZ7Ds~fV$jv?awcZ +zA0Z=xcmGIx`zvq5u|lh#0_1G#fGVB+e_x~gYju*WVk0*%kK${){9Azw!%pc2Oc(~+ +z&cvSp1~JPJ4V@vK@YV=(isn>v&UG+%7k)QVuUFjg!4=EM`;+E`GzRO^QViHUEY> +zu2D*)H~QIQ*UiH1^WcI)c#~4N`R!6!)1oFWi#PNp5ELlz;c8FPHJC6V`J2B1H)t+D +zmBPtK_Gm&=&14p#1JEt>53xJ)4m!fiY1gu)A?Tu)9xq#A?m+Lgh^0tSbViEVY|y^g +z4jhJ1h4u%C*w4hO9Y~3dd(IrgDDTn}!+nzQbQ`YC#v5n+F~Kfzxf$&Ovy>cWiqd#B +z9C-g~eG6#>&ii7Cgdms~jNn15CMbhxb?4~@pgfT@l75_3< +z%7&y>^d_Q2qG(CJ28B0)a`mATy?@s14h$E`cL6KJ7LZ5t{cl!?imlcEkVSW^Oeg~C +zcpjcH5(6fF2!z|M>u(1RS^_ZpP+SbZ1uC-`68jH^ +z`jP@HCWReXBdlN?SNC)9hH!*F5Zxv^I>~@x&Op|eHccW^Cp^;)42K+|vv%(aijSdE +z(zRSANo~>9q_t}IM9+5aVF<6VV8)WoKEP%)HrO1ka;(=?Z_XM8Mm9~y{U)9 +zp}^*=C^n5gFOc3LiWm5>)PFWn|E81f(KGrU*Hq6F)O3N@zxIN6fXfvZN0b>L&HM+E +z=^ZrKN0j|NfcFWt^hCN6N&lPKH$PH3<3Ezxl&{nZ(qRQ=4s>l?Qo64vG_d`Mm8bGUUDDqay!AreR$B +zo5nj1qC(oFF06@|<10Ac5f&1uugDFq)^;Qysi>Zb)6;#|#x5c_jZ9-p!R7n5&Z)Tg +z9iLBWs$2ziAesLdLlh+2Nc^2EQf2r$Du^+cHd6L(043ZA%~JitXnK!D#Uq>>$;{zVc(c_Q^HV#@K_8b@>Q-Jj5157mdo@J&knfEJdwK_Rm@@;9M1UolnV +z)ds1O#PI2y#hgt$w_iMW_l(hjo6D(Y)AJYRFFC>p}hq-dnfvigd3R~}Kt*dCOyn5henB033;FwO9iRD6!>A<8gJMN+7)+a6=vZrBx5ZPW(jRr%T%KorX*4$K-5$v$JK(;w*i}V{2 +zV4Y1wQat?@#VFRe2quJ$mlltJ*$kCIfhi}eoPx&UrP+ntTis^P)vswHSQqwHLm2MO*x=a$`Acv@G>nlFvCWHC^81yr+h)LYy8`vzMfY +z%Rp10-;}-eW{`40uWV{XzHPuNqrtf2CryBy*!`+~`@{O~np@ +z^;{F$Zh@w*F$&m^dMQzjpMl*_Phn!B=2TEudpS|>Pa +zsl90Su@kv&M^dSTdOPmMq_}A-PFC%?>P@P1dEuw$bb7|{KzsuaLxqPfFDv+CEC%EmaamJC;HpTGP8Id(&s$jV*eVDyM+Wp& +z^`!+}p8o!7h~ZRKAtgeC!XbonimNV6F+fPnD}tU_N~!9^a=pLr4BURBNC+^|FKn|a +z?2$p3+J3&z&9XlP*&45Ll7XUobJg%2CPngyyCbyp75hP?O>dGTIL5WR1)7v9VXG{Xb*;qglC8y+%|Y09zIDQ22;atF>q1n_vbBqYb}1?3Et5As^|-) +zV>S}+s3B85B>a%Om{GG!I1+|7B!1^Q{gXTWC{xWo?IjFKi~+Q5P8Nss&L|1BMrF!@ +zuU3sRJ1^BzmGdfSiVNtn-YU*1k|ODSBTt3=yz83^Iq^bwNMcT+l{OdzXCi8{`^7P; +z+ad^emV?ft@|1T~!*V*7YX0eSeU9Tm*K{d_QxulLeEe$Ipk-bQf1VI`4z&K&4X^~q +z=EB&UsVrRQO9m%rpu)^pu5SMtvvb3#&VH5dvlE3zJ)O}2&GLa$QRBqQ3+~?PRgZ~v +z#uOQQq+375DbyI=4BI0@cXUg4%@|Y5!nYg((mvJUl|i~I&(%;Jnpt00!#GSlgPdB# +zBaJ^g!<^dW9!K`^zXa*Q#%nzwhwLL=kF|lbM!@KsmHKpDLo1m3bY)vkiqoieFNj_> +zU0nOAUD=(Y9A$e#aXf;=-(z8gGocnb*K41Pk9=2J@ikx4ZO)Dz?++645026|rqIT4 +zZxW>5rLpe#$I?fUiv*`_=hLxziQnCaeel3a=~p>?G!sujYFKb}+HdQ&9G%HGyo~3Z +z3OrCHAj!MhTJ9{73{An-DVA!=WNUhn=w#4yUsn{jhP1HF^2grxy_4ry)jIyr +z|8q{1Wvx9^3Q&7X{@t1SpYJjMKaygyqRwB=RGvnSMpqe`ri?weC`wUETNFJKB6EI} +z0H}EG7dDBI%TZHRQ*zR;!e2#l!MraZZ-o(VY(R+67Or^H*`3EZ6FhEzK0ZHTb`bQu +zjq6SahDt&cLTy4W%9ZD`7>z5uY`|L)pFxFsD3bv_3_k?7?`4J4hfFsP6*8?XuJ?Vt +z#B&XJS5Yh+iNZ{^!|^0x9&J68t2~oQ{X%^-644Cokq_A|So1#E_CRnz1*a`6hB{ZG +zo(}ETzCBP$p7a*SRyb55iMpv9_!hExW_&r&u^Gf%#i;xzR3=*UmfvltxJin#XCG$; +z(kTrvpDuXU{7r=cMOUZek~@M9_SFR|6=OV6%z#3MsGZcapY9?x*vO1Xji&=F$e7Xe +z$*=EK;%DG$lCjU%Pk5ALQP7tch_)s+nxeKaIZ8SM&Y^-SbQ&iU8ehSasG-$gLy^S& +z;@r`y^(iUUr5~`C@Z%;Y)&|p$@#HiJzGT7%PyZtI6SIWKQvs6UHiZ9pr2m(0Z2S*` +z|KIg}wZA)3*TVn_*KmV~VHJmd5KSS6jOKSlO~AY=#vPKP;T4-Xpy(m_e8NIRMvKH6 +ziPR#g1Y6nXWIEf-hw{q~-wto9+&>|{=c#`pIl0BcQZ|HrA_L_dGbV%lc7cGa^_~>CI1u8$#%` +zPY1bhQ0ZOwj9%Pv=*!(T3RlTlF8at-yd{O8CLFvqt8&Bl8x4I#%)6*)_?E+G1`yZj +zA-?M=-)iF2T4D62a^0GEi=23?aBs=qmIT;(EjC|BJ`TQBovSA!$(5u;vl8n$RXh5w +zsnb%Nq%}*T4peiN1TBN4_W#_2i1`Q0}S^~#8x(p(Xg7orgnzU)=z3hO&q;B)18SEI+ +zr#}XvVvIr%!7XV}f=m7ZTO}9949l)BvU+ugkWQ;SW9Z>$~f?|_?=#!1vJ5VmKUR{$~0GNkAJSFV7{XY`1P1}9tjt} +z1ld3q1V-W;V^+T9sK}K;U0GdOPN~FMGIJ<2j*BQIsWw-X(w0in9u|~YBXsq`;jY)) +z>i6JEi8gP^c`;vN4NQubP79lK*QAWIxExD#YO|q}whK0QTBnvwvNmqC4UXxXfUWkT +zujg@N;V@$y57AaFj;8=k=`n#kX@7({5Os{^%ZP6G+_bO&9^>8Guq)}w3O9au4zNb +zk=Pp}U)h#)(5$carkLEFQXEhruIU{}T)@;|mk$_hD&Ly@K#tmd^cT_*r}^&VU<%Ab +zPw>(jnhf5fPrQ7#V5q<59AL4ze50Ycd;_5`goIZx&dX**&=>E{i5ypQqh?{xd$CKXERp;-261TV!FpV86fy^- +z_$gx+kyt6^xpsHr2zHf>;-2$PVwOX+M7Fb`-GiL?bZFyX(bizk>T4JRE8!oY_wD!= +z;N((1g2u;>($5t_#?mg$oo#I+?cAPdl(CDh-u3v|5gw)^J|*oR+@!P_uj#8@FOYNW)S3+j;h%RtD2iX2zlP<8A4t_ +z#j{GxZf`FuFZpnaAZD5^DnrFR?mTQ_C^3^4FAN{4o%aLGsck3m4NWcnj3Ik-d7;zi +zach$~(PRd%Bf|V(Z8+O6xR$j|5~=#6hWE%dtPNbfoUnmF(CoA+7Bbv_54;##hjl~T +z4CB6SWlm-9KoR6Cl;YNDf4_E4O8q1Zy5IO3p0WMvbYr{jiw*n;IS_HxN=(>nb8z?9 +z0oyt?A>#Bcly)BX3<>=h$$ZX0Nf5VhhkN?q5QKs++RUr;A*mC;a?{PymQPK&TVan7 +zJfIzprEaIteX_QIE(>8u9>VF`mU4&4t8PV^zdJr}+6@e|5MusW{T6yUsrHPR<;OXy!?f>E6 +z{TCZ!c7l{#KR-(F3>c`eH=q1K!9_197P8Aeu|gDe0SU&l(2o>Gn@|`K$S+AXGP)0- +zKNR~Y6^tvw`!rXlS)AJst|fNY^tIof>b3aMusy7g>XXGNLoab$Ay$zQp?pNe)vVlt +zq?J0d>Nb!Ff8l}a)Yxh)vrlVEaZUa*k`%sQnLNqCK#0*)^k^wfJ9k>Y4c=6}`}t!{ +zJeQjGC66-DKiIa(N-2cc$k9bw{qe=j+x=UR}VpX6fn6C^rrP4!BI^PTCr +zE|t`C+afO1c5?}=y2{oKmTEU{RN;mN10JK_s1}WN*j`M(x<$2hB4Fa9SUsdA$=! +z;EWuRiSQFk;EZ$;YRIxzH}dkwe=!CzS*x{30whIHfG{HZ@BisP{DptF0SXy7nE-~a +znAkd5I0I%_|7V9#vC`jcs?6RrJBINsFB(G;DfFGiZ-xZXl7@mLmV)!oK;T)Xt2VBw +zfFWgmJ42}%FZ$k3Vwl%7*wWD8$U!iZ$F+9bKrA=hARux~;-{oPdAgHe +zm7Uux^K5s@fBJ+NOL0&Z9;#O#BAG{$h;fg`v@Sl?u*yjKyRle-E^FL8d+V0=hIgI +ztfuLg4PstU;e(h-)wO^%N$kT2`q440+wMg*9c%(^W<3=@btqme#CfHWr(K%=t^rIF +z17F^lj}?ufehl^g{-+!Vbm}n7^f(ue4q43Xt;nF)kYBvDM@vR)(b%Jv%P8FC#17tpr-<)G-!pXcFeA=SB#;7m*~bgu +z8Q^MM3bG}BMAE?Gho7n4&>z?vTgaRd$n9~x9^v@I9^~gjN??%2Lg12T)-KW`{8)R9 +z8l0AXzg-QWtVQGwCXpi^U}k8?Y*0N;N348mQGlR6bV%fubz^XVZbh8vF34~z$go2! +z#E+|9@+D9x{Q^s9Oh%`l{uzm+u`$$LCye&v;1)+b+)(%+ +z9>Z1WgE&d>9fQ4}mt#yFlWu$N4$^jgu|5?KOTeSXN!qb5C +zR$grX>X~#jv!z2I0s_|{iZmwmM#L?R9B&eopr3cf6H8DNRTAG!pAIodvLqc%OfH +zA0JG`=Khcsc6ym2xXk-Xoyk4CM}PfLDf|U?di_u@%gdEN4@Z`rk;XbbFOj-bnD|rR +zsX?yf6Uz$g`yJ-A& +z?YuD@n0vqnuL>`6uwjC%+U>zNx%ha)*DNw(B@k{{#k+@ZGqW$w*;HvJ$LUz9C(1)O +zJBk()2TF9*R0m3wFs6{(RIih0oQoZtuiU9KadJP0&CZ&FjxDsS=b3V9Z-JxH&ziEV +zoGT7R1e?_NNx8C#Rn;rzJ(wDUQZ2kwWYHl8G91A#SLm&x_Xyv})jPu;RUJ{OOanqp@n|Pnit75z)o%y4wo0JrA+$AZ~^V +z)DmT@y~7{az}*wo%^Igu@6fX8jhK72M37zzHIC6*fH$ZTZLnII5fkf~u$uQ=5Sioa +zkfe>&+{gy%&5fAwVpva^o9HTMi)NhB2(wkVeVsPm>#eS=)5U$OxpaEfxKr +z&b|Vws-}Bix~033?oLs<5$Oi$Zlt@ryBq25?vm~nkZwdu;(z_rpT6kl_pbk0>#TEO +z-FcpwIp@yI*?Z5kQR{?}v4j(Q-$mMVo(fb}m{5J(qtB*!Q@&&z+EW5pBk34{OdT<9 +zD9p5`N?a?0h`>IZRFTLp)~GVy-1DP>tNBb-TU?-CXWrurCy^ +z1b5d=SrF}08-g0@rzIWLX>8A2X2uE)sJL0V3LCj(BR99;;&Y;6lvzv{v>a^)dBA}^ +zQ$)n3gdonWoCXMl%z?_Ngo+|pO1j|m*;qB0@cg-25UGOnZEa{xU94|7#-g600fq8X +zBhBy37?MFT0uk)_|x@|g!G^JC2(e9BI)eR3) +z@~BhT44M+*^;0V9go>Q1THXUUJz##OJ~w3`7;Sak(rF%C8R^)F6(?U&ngg0qhX?1T^ +zn^aVL$TlF%s?~=3?Mh@`=%ycoz@orN +zA0zTF4b@?~;ICSofVkv$z)viLzwFkWxzh5+M>KDEiW6f9j=xowqfLn2NMhR>yZPa* +z)sUBW;udU`9d^BF;9LCIQAN0Wte0^UlO3OS?21Tm<3ITiJiolxKiRkyh@-4It)HjK +z_wAJ;qNfaky8*kK_>kZ2A@vE-JAI9e*=;5x{Y2W^**Y#C9>Lq0WWAXQi789j)1a%W +zqwh+^`^y!FDI>pQ0lsGpIc*#m_)9uW_8Hs&7B}9V@az`@r +z2Q!RsY{ZTU`tADK*7}y6Lop^{9FNPOM&Uf8%?ufM@u5qoCd(BIqOSHpo}M%7TMcP! +zpw$-a$(BKy;3-jqk_q4x?p?>L(OwfB~g~P(Dnr3-s%%Z%|LcmasLGWY1KU +ztDLA=!Xq3{&FmzhrMzWgGo7tVh#b+^*8NP%w&1aLPjx^^G>RF;_?%c;<#|FvSIm|bi#%%CU%|T^V +zpU+G;5K@0Z)93SkZX&WYjKldU6>^w2ZYuNL*6my|E7CRS6>sCtYw|mGdQPgoL*cl{ +zc}PR-b5p8uz=lhWbI#2~ZO>pyKO>R{yCT&@gOBaHEfh1SqCA~+K%cd<41wp|TJFNu +zg=e4Qe<9KRfJ(pw>gVzK{cKdAc_KH0Y3q!LBCt%TRTb&0_gcNBpTNscWCxOPr%HDq +zr8f=k4hcd{tlskDzmfBwC`Y_97ECUo#-1PAKNJjBW1r2x3LX4F>W&Va +zSFIFixnwK~h@uB-q|an|rZx?CiyXDGNr!KXb(ld)bT$cE5H&s&jm^ohoOe^V@sf7G +z(4D8o*E*hz5`!+D?-mbCMQ!->4#|y%kj@E%W}i%R67lRZYDU~MAJyCWWO^KlCOgs= +zZ8?n(`4uhf+(@oV7$@6vI(74c_bNbn~#pe*CoF6dsW +zxT#_WRQEb&cu(DTmqp>V{aw!yTrq8G#~gzwl@#1Ugf7P3n +zb=+#53+|VFc;G)Lcl0UPesWEYZ`yn(H#Q}eojjOEB8892_<4e&g*mS^Jt%3AvOd0- +zHRf`hUCpYQ&;mcyfV1C1l&<^yZPM$FBG_xEohk2Ihkix&3V%}E951(|C1UY>W}Gc& +zdbK6~eB2zU4A^U)=QaL$(^vfWcu7yaxCs(6A@zM-z{H()&W+n7l|h3N`HFn25!@W< +zWKG1&chsmU<%3_zR%@j5L)Q|fzm#O#gp9?_B6=O~eS@%hDGP=pe@ztU@vfK7*#Fj* +znF=0=Nx|Vd6*t!QJguuqNH!*kzoD!$y|CTTZY>2biK^Sic?Z@ge;Sm}6OZ!~0jeJ` +z#alw?WrD6xST55YSs4k%H@qrON>0Sjla#X!s-|$`oRT)1{qA^QxU6q>Rl`<()C<~w +zkDrIhKR_bTXgz=H*M&b?dXNc*iX?@HDkc05cr}z6Z;d;YRhC9wYa8r3x+sn9Gv)qr1p#GjZt=r&B;Q@G>QFc6!b=K1d})Z(4D#>{jPUGNX#!mJ3F~TN +zqG?j;*TPVmp>btSxY{kUP2O*!G3By-7j +zL?<{rW89&sydsQ?lHlH~W=vA$&h8qG8AWtxV0-Ad`PZa%AFH^9rSXmmZ{E^UTgl0A +zk0uZDpX2$t)H9!0M5y*ff}67n9sA*Pp2BIiN}Yf^Fn@5u^B#6p&kunksiZVMZrmM(({ +z`zz`j+S&2T`p}h4^>e&czLy^qcZ6>_?-Evl<58M%d3sLbJW$oa-o!<~X&(#knw`v) +ze>pribAnjA29kuB;|`o(C8};KQYiK;7DhO7D$v4j_AEZUB1x|>G?{Mpbs{|#akLHFoHIH9Ni*4c8zg~AzM75WYtgB4{1JgUt5sZbFF5n +zqR+&9r6seGY#ZQ(%Kj;tO|D;SmWUfZV$=VmnB@s=6|tEho(Pe1Sa)gmuHut$cZe~U +zCmGjLa$XOVC@*R6vA%&n=?Af2 +zvk@lUp}Nt`uF1UT_c%bj2?ePL)lTMIHjs#?rNt+s1m%*-#MO^SKk6 +zu!I^C6Y+FXFb*=et)_A^Tw%pRp6w+J^MgZHZ)dhC@-{)(wW{$pp+j^+qRwih_)SiZ +zxjlzF?87x|!@Q48>8FAukiB2zz%3dJGU)DH>9gKD*bA{47k+pKTXE&SYfl@@-5}Wb +zWqq~jD21&#^&$NJLuG=01=GRjzVqC7D#Hkp?7nvAuW^))xFs}3ndB4_*o6iR$j_<^ +z3BiMWj6e3foZsiz-9ReSU~mLATB;*=jPN&ME7qD<$7idDT|iemj~#)9k7l&UTw6gL +ze%iBTSuml0fqCdwoi6B1vlTq%_VnMn$VVp)Os?eKcf>x!}~BfS_Toklq>msUBpS8Nv3 +z+gk6QyzUJGN1eo~OxPt8Rb(h440VJfMU#t>r)K=P=TDh?5Tp%iFDoARp|%kH*ZDh)vwPssBU&f +zI_XM4sJ;p&bl=u{6WnJ3+;^GNxaC-@^wzORFWML{1Sc4il#q0NpJHD-x~*&;8wj0u +zv7eq%-LYrYdU8{vYYEb4gGE7~6;noyS=U-U8WyA#o&Q~ZC;e31qO=iX1{SMxgmbqT +zZB{VN9+Y?O +znniHqU3+8+!@?#LUGV#7{>?7xL)rLAK_q^g0yj*@HQQ~UoKjZiv}753-=eaeDfLSF +zHRyaM=sK{fP1icTTIOYAcT~j8YkYNH{)v+0n!#mfdjBC)YrW*EY}c+Q7yCWU{{1Tg +zhuEgY3qpKPO0n~v_k6Vv4KhapX3a#cFTl+!j +zDpSQ3&JdcISxck6z&kyP3=c^k59Kaj2El9%&`a30WUNOqPmUp_$JDpwP~#9J1KY8E +zMF|TVIctP9nzIQ%)((ax&YYEy>z?7sVc7O4oKkpP{~!wR%%=c62mk7s|Ms|la~OON +z#E?CF^)&!_623O3Mtv}zJjqLbfkuyFoh+ai3;7ukGA#H5+@VsOseSTt&rbFg=zXjJ +z!FV^sNoI(B9u?mr=#|a(3YX0h_x8y9Ur_~&X7 +z!oleo6;4p+St_QfPgrVpf%vgsCc`$=aNkF&KDAGt(cf7#w@K7$H}S9Cj;hjbva27Y +zS3TgKO{OqoAU4+Er`Me|RV+TPv-5d~J7(vzJKI~DUvH(^AWwv}KlI>TeGSK@NA9xO +z*jdK$91`?U#UyRDI_ZT4duJh6t^6kynj==-V74WAA5Hd9GN8mfNXqNB$jLTuXWw`!)@^ +zm*<0yO*Bj39S!$DFWzA& +zF|<946vxy00F&p&xA;Ox%+EWwOz@$Q}hyQpg)PepQB`XcB +z#G1|skM|fnJRO*f>kWUeVTK@mLe%88qQBY9p{F^EEZMj>qTHay+&x|iDSEjILQTt +zuLUpX_OWv5A>(RxBv>b0eGuuMC9;OS&&e~nK=Nk8nb$^$3(Xp&j~cgq+oCW~wB<^o +zNh(U9gA#KVr)})Af&_h$rq7@@ilI-T!5FKp9Ev`u@;tWARF+~cIZs+%QdPD@FIz_X +zoQSQ-bO(Z1ZWy#nNt9cGbLrheQYKS~|FcBbO`gDb)E1P{g}l6Yk++?>PQo>)CBl~GI!eC$qPRAeECqLvhO%EB|J*i34aDN8EU9+MRU?vf$fWr%!gYDfz48_LvmNPR*#7~Ld8L`7p>DoJ8YnUlXvhA`JkE?Hsb>cN6 +zLOF%gV=Ica?Xj!;vVr|+K7X;FqNDTzu7AEEa#az=j%XcCdT=k^(I%HG`*3sJUA}Fysl_oui8nUQBz1B +z+foXLJI(STPG*4Qer6gF1=t0@qcxo>dMP{Cx|fxQK7G?m%U_O;YIILLW%wnu+}S?8 +zM}MsFlwb0~fqd6?l#B!8hy-1K=b?w=BpkBWg1hE;jQSP#vgFlPy7wI)2s~-QXRc0y +zy!PXgY>!X%PauKm;9k9)+%s^L;yl(W)vFd;(Ac9Ba&7CV+DNr%PhLiRhg=DFHKPr8 +zHLJ~xij6UMKWp*?xF#CZHmG$QktiIe!*)^y*^>!+JUns*Qa*$JP`}wB0`2mi%<)n- +zJ=nSp4wjVwS1Um4ZURx)FTI@4n+cX~t${)U(sK=52+fsubrd6b-1Zz&N5k}G5Akp_ +zuO^5m6yXjs9@~k6$?h?Fg~7*;{ft(g7_T` +zkTG9N)ObVMH?WuFVDYI})`wTt=N6wp{6FI;H;J99n{0cEqlsFl_5zEVe|YBKmYhv- +z7Mp>%{U(;$I(fo{`2uMJ4mADqd$VZefhQ@^Bw{Tite +zo!X4r449h<0CO|-?*rFwago1ncnFnM{g1jwZ5_=aQLY*aFFAT9&0r9E^Xno|2129m +z9B^+7elBIduahzjqC4~`Y3o%+pjd=}E5Lt0dO(|tBI=Tu%JBu@4_)P8YI|^b0D6N+ +zMWOrpwKO1Li4XpUK0RyGFDO}*Iw!&-t(S(H)JoOu_+33!+vUf~ob}cq2xuhd_oh~g +zym^&F7YQq8J_U+C`!rNL1<+mE8bfQ)`i*Y!UR49s{AEsIwq;C37tL=8VGqHW(p}TwXCBscLn0{JQo?XHD|PG#UFg +zKg&0bzfn+^F=OV|QkA1Mvb2!JdQG1|ml7|4_Xw6+}LtR +zmOkcXcvM()G2FntxRkYjL#DRzI5t>8;j*>yZ9@buMpOHqm+l0;j}{n6zOf>X|DpH* +z)=lKJC2kco>8qmBWKy;S<hc)jk-7V!$50Mr@9Gqi>t&$^1zsPmgfNNguTZrL|CF% +z&c+-i@f0#bF?Kw84v@JHA^kIiS(=Dn4zkO}C|3!|p9yh1s|KXmE!Cdd#_y_$D8jU+ +zL2V;+^H|X#uC3f7jCvWYiNM7NkLilvd6}Zk537Wn3Vaoqp9F}n)s9OPUwfX_EcLD +zq#Vy$U*lt+4JQfi1Gq?R{^hks}tXQ{WNsGwu1vd_Tka=UE5x6 +zlK}V?6aqGs{wv9eZ$ATGdo63dZ}9`aNKTZ<1J)J(Sz5ZZ{1D9|kZ +z`OruV#BfPd%pLA^hbriGOBviIZmOPpg +zkJDiciB}sZX9g`>)X&sc_3cx0(0Ba=uOCae^|G${Kn>p(y;Pl?*lF0B`hm8qtH9Es +z-leoN!?f|OF)IlOSBd^Kij>22UjOTX604?8Uy?h5cl~yljNuwLar>stTSTv^zAWW8 +zw;rpeiIkYj@on<6Wp=o{zE98gYP2EC%PfI-P}Ft{KQWx +z!{^NhojB@Cfyiot4LNl8L$Tbu^QM>YQqxSH&~giAy*3Q@ +zGpyY1r$QtWV>OdF_QpJ*A`)`LAD7~#c^7v^4Ies8(4)`5R{^{E&hJ1l$&OjC}x+%ga%2jHa_71;%%;I#qls(TYOcDBKu=Ag5SEF1MaGX$H&u9_oMh@3+> +zr4(mW(fnx$P?ccoErMvfR~G+Vv66v`z+wVI^bEclBYq$Fe+lP$6pqmGNH$8u3@ub9Ng*PQ0t^kcQn%Y^D#}*59CObKfB(cird~1=G@1`RF4eK>xJ7Gg +z`*I(Ycg;*A*6fScWCf~HnJ6Ed>4v6X$R{k{Lcz5Vtm +zn8^ZiZ@8IPT3S^ZionIz&WU*QXh8B7@gTq;Mj!>6#jwuRNh(cF>(0)b7P@D?%zWq^ +zsrHU5xKK5?$$iLvnKfx+uLDV1-eHxec{J1j*tgy=n&y0Q|M}R0?n#c7X0P)5)GU1s +zAq*QFOiUy+J?alCPsHm-P6HFDZHgi1;4m2#IA*}hN33Lf!C%BO1W1OZgdo(ipW)PD +z-W(o(cCz);qBc;8mFtnQFH$K~o0e6sQjiT@PBAyElP@Y&#^j^h^E0PoD3)^S(iCRj +zT4q(#H%{gqOlrdF!ql2Go)SxXD@-FlfHat>SJPOc(wM*&8kI4GpfP@w99NsC`nG9| +zoW+%q9NRBbdA?Ak%mg&~6EWuDUcf6Xa(teqfJsL*Ki*05xk9~d{P{*BOP3M)k73J7 +z)rQe!sRK(OpCMS}5c957?^YH5b@lkv?^sE`;3WydAG&!hIh2@#zv+(iXg= +zYzw$K2cB^>@hWeOUEeARgF#27TvPl6r +zI7jUgFb$|FT>)NN%|llHgpNd*JzGuCwWnZx@z6nYS^*BC?>^wQYA0NV*v>i_CWMF5 +z4mcdWBLPFFCslGCLU_s9UMX)h#oVRgDl?Ome$O|lmy?J#K)FU_J|alkyN^5x+u?ot +zJ|53dFL{Ftj8cq9J8`XWJCZe=ea!L_Y%PATE0(PYq6NX4pZ28!%^`heHk!VaTgR@3 +zWBz_c;D#3lt1~5Eiw31KO?-_LHzyl^{JsqQrQ=}ebopoFy|^0@lu>?gN?p`p{rb6A +zlfyBJ&Wn-|uv=i>ry3XsmJw;5{CoFvlCgEKofb@N%aXt~4fs$~WUBI_s6VMYtZ-=* +zDAYW)pQl>C`vk5xw=w(S4*sgGTQa4ais(E8dXg&y%sZ=jvL8PE-NpH(Q@B1Gz{#!= +z*yHX?hbDE<@xV0f>X5!LsU51$kFUz-q233fi=D^PsT1SUg(+P_g54!tKX-n^20kX- +zQVU;zAyv+OZr0=Gd5n33Jlf%U1p)#y5pYg6QF=Wk1$oF%+iQdsfT-cv7~Y}1Q+>`g +zf^s*|$pm^ye{PMRnKc)Q6RAPC>bQ{QjF+;bAGik>QYjx&!9qO8$!O}m63pR$uNSWr +z-0BA&zlobgNbU@$-it8HlQB)gC27y?)(Xsw{iO7_VFpXV?LYrk5S}HvQ`UG?r +zgZLhkf$hM!cnIx=&bG6fm5W-B|5RCooxv`LOB%KGULVP+ng&mbMi0dvB94axtpOok +z7fiiiJ^kl&(HAa~cWhC&`2QS3qMvXjehs6(1&q-gzmL(fjyAS>X8*>fkQy~4*2RP3 +zH#%2jR#Q7;JT17y!iOx-?Ta3PhAu<*dekOgIU>9qYb$Hrl$^;aY%C?-u<6m3 +zgNiFq!(GWKISgb4eQt}<7XXvXcp?a#BbXHq@%e-F5OCl~)_NsYA|-OH +z%@;bJG5dHm~aqYBZ6C +zf0+V^=15swb$7c5wtUhjgtf@ZI5(1Iyn$&)Jw?L|nW&g{o;B+u*J8y-&($$TQf$Y) +zi>DFtrSyjU=7qD^@*9F%avtFo5 +z!Z(D8@iKr@R!HzHr05y$=u>>g +z-I`UUPiA;8gcQ}@y?}M(iD8Kgul>QFoL@6cc=jNvV))ohpG)>VxhJ(@|FGz~cwBEz +zN#e&dl=O3!bmp`Sqo +zXn*|uvHFi&>Ax&C_GKntBiz4Ih0FmG1MB9}*2|!&216`&ppd7PAy*O{*Uaq3B8Q3w +zKSgzUvI=5g`#RC;b~_||ouBwIzLPC_HvI!H6}{F_5=?u;9fxoD=D9VFTi+^BJ@+q7E^o#gJY=^p=!hi +z{Y8!>QNu-%Ijt3hCPftTvS_;585mZTc#163&3*LK`=CmB} +zl|$KYFxa2^ub=C~(}askIugT5HpVgNbxBwx6_!GYFjg-#yP{G^b~?=`t3^8!>Oju&EpQ$+ZJJv`W>XIz&EvkSFxSm@3J+#!I}EB(U_u+$aR +zp4ye?&Gmiy$uY0e)5tu+e!KDdDhR8@#lwy!9O!6~y;VilL!A2cZI1&Em3f%zDm~CS +zs-e^j*KtoSC^ccWhK>g8?gsK5a^QNXy726CG<6AC!`qxUJ@23Dly3Xa^Fh^HKB3JB +z|B%oFR`QMmoo{Z?xXqWr14e+19Ax->eUErRK5Oe^Jc;TS0(o==b9*)&4&Veoun%8?&L8u6{P)tJ8q<+4tgKFV&uSfc4ie%s&8r +zWG?z4cK*0V;i~6hXn@vR0$Tp{_WwAlJ%IuL{TtxpRUKe`=itcu*47XpKWn7(Q(O5l +zVh +zOHD2hP=FV)Fw>K;urPUR`DbXHb@jy_0LTsCDgEjY{&7@$!a)8J8X&uC`ql=piA>1I +zRF79jN6*GaQp;S+;7789$92~!^K5(rs5=6{p7+nX6F&VTfugmRC15Wiz|^5{WbhWC +zU=2`n|8w1?U2%;z0bPO#s5||SiUY3Ip6>zD0)Ob1$M;hNkgvh?zg2w1dOrvi5E^0* +zsOHygOFxck&j-{$qW>e8+MjEDwY(8{0>Dcp0GRoI00OSno=UiX!~|^Gv(+*+{WIEf +zyF_3&p#8CcvE-j!>j&^3{Gt7P78bT&lT}!L%~lUElm1Lm@%XNF2oenP1G=>a?OURO +zA9bzvj0LDO{{i~@T@!TB(|P-Un&XdA!#ZP5hybX*0948!kpF2u9>6a12h?xR@ptU6 +zmHu-_JWiqd1G?HX05InN0rz{i{#QVps|8HsZ9{0xMq-;M~4qp9{ +zsf%=y;7LV)yI6=TqrYwzr!Sriv51@6HzorX#O!Ziw{U=qJ +z*59c9i(30*_{T!yKjDdW{s#a3PW(-F{4v#I#nPWtLMH!$>RYG%ukLy*`uLN?(EMMJ +z{9OX_af=>niam3e8g1OY+2!6~G|HfAP +zxFwGxG=36AX8lI=+vEDTpW9=v_fO>b+~1IYf0({O|JeurxDk)NjX$Y^-u;d0f6S$i +zooqj0_X_?7`+dOpi_7hC10I{=e=^aQ{>Jop$^T2={f`DcHV^-#0V@BE<`>xS4f=NZ +z%h>nWPWTgFsq$ao|97k5 \(.*\)$'` ++ if expr "$link" : '/.*' > /dev/null; then ++ PRG="$link" ++ else ++ PRG=`dirname "$PRG"`"/$link" ++ fi ++done ++SAVED="`pwd`" ++cd "`dirname \"$PRG\"`/" >&- ++APP_HOME="`pwd -P`" ++cd "$SAVED" >&- ++ ++CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar ++ ++# Determine the Java command to use to start the JVM. ++if [ -n "$JAVA_HOME" ] ; then ++ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then ++ # IBM's JDK on AIX uses strange locations for the executables ++ JAVACMD="$JAVA_HOME/jre/sh/java" ++ else ++ JAVACMD="$JAVA_HOME/bin/java" ++ fi ++ if [ ! -x "$JAVACMD" ] ; then ++ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME ++ ++Please set the JAVA_HOME variable in your environment to match the ++location of your Java installation." ++ fi ++else ++ JAVACMD="java" ++ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. ++ ++Please set the JAVA_HOME variable in your environment to match the ++location of your Java installation." ++fi ++ ++# Increase the maximum file descriptors if we can. ++if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then ++ MAX_FD_LIMIT=`ulimit -H -n` ++ if [ $? -eq 0 ] ; then ++ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then ++ MAX_FD="$MAX_FD_LIMIT" ++ fi ++ ulimit -n $MAX_FD ++ if [ $? -ne 0 ] ; then ++ warn "Could not set maximum file descriptor limit: $MAX_FD" ++ fi ++ else ++ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" ++ fi ++fi ++ ++# For Darwin, add options to specify how the application appears in the dock ++if $darwin; then ++ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" ++fi ++ ++# For Cygwin, switch paths to Windows format before running java ++if $cygwin ; then ++ APP_HOME=`cygpath --path --mixed "$APP_HOME"` ++ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` ++ ++ # We build the pattern for arguments to be converted via cygpath ++ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` ++ SEP="" ++ for dir in $ROOTDIRSRAW ; do ++ ROOTDIRS="$ROOTDIRS$SEP$dir" ++ SEP="|" ++ done ++ OURCYGPATTERN="(^($ROOTDIRS))" ++ # Add a user-defined pattern to the cygpath arguments ++ if [ "$GRADLE_CYGPATTERN" != "" ] ; then ++ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" ++ fi ++ # Now convert the arguments - kludge to limit ourselves to /bin/sh ++ i=0 ++ for arg in "$@" ; do ++ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` ++ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option ++ ++ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition ++ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` ++ else ++ eval `echo args$i`="\"$arg\"" ++ fi ++ i=$((i+1)) ++ done ++ case $i in ++ (0) set -- ;; ++ (1) set -- "$args0" ;; ++ (2) set -- "$args0" "$args1" ;; ++ (3) set -- "$args0" "$args1" "$args2" ;; ++ (4) set -- "$args0" "$args1" "$args2" "$args3" ;; ++ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; ++ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; ++ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; ++ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; ++ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; ++ esac ++fi ++ ++# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules ++function splitJvmOpts() { ++ JVM_OPTS=("$@") ++} ++eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS ++JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" ++ ++exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +diff --git a/gradlew.bat b/gradlew.bat +new file mode 100644 +index 0000000..8a0b282 +--- /dev/null ++++ b/gradlew.bat +@@ -0,0 +1,90 @@ ++@if "%DEBUG%" == "" @echo off ++@rem ########################################################################## ++@rem ++@rem Gradle startup script for Windows ++@rem ++@rem ########################################################################## ++ ++@rem Set local scope for the variables with windows NT shell ++if "%OS%"=="Windows_NT" setlocal ++ ++@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. ++set DEFAULT_JVM_OPTS= ++ ++set DIRNAME=%~dp0 ++if "%DIRNAME%" == "" set DIRNAME=. ++set APP_BASE_NAME=%~n0 ++set APP_HOME=%DIRNAME% ++ ++@rem Find java.exe ++if defined JAVA_HOME goto findJavaFromJavaHome ++ ++set JAVA_EXE=java.exe ++%JAVA_EXE% -version >NUL 2>&1 ++if "%ERRORLEVEL%" == "0" goto init ++ ++echo. ++echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. ++echo. ++echo Please set the JAVA_HOME variable in your environment to match the ++echo location of your Java installation. ++ ++goto fail ++ ++:findJavaFromJavaHome ++set JAVA_HOME=%JAVA_HOME:"=% ++set JAVA_EXE=%JAVA_HOME%/bin/java.exe ++ ++if exist "%JAVA_EXE%" goto init ++ ++echo. ++echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% ++echo. ++echo Please set the JAVA_HOME variable in your environment to match the ++echo location of your Java installation. ++ ++goto fail ++ ++:init ++@rem Get command-line arguments, handling Windowz variants ++ ++if not "%OS%" == "Windows_NT" goto win9xME_args ++if "%@eval[2+2]" == "4" goto 4NT_args ++ ++:win9xME_args ++@rem Slurp the command line arguments. ++set CMD_LINE_ARGS= ++set _SKIP=2 ++ ++:win9xME_args_slurp ++if "x%~1" == "x" goto execute ++ ++set CMD_LINE_ARGS=%* ++goto execute ++ ++:4NT_args ++@rem Get arguments from the 4NT Shell from JP Software ++set CMD_LINE_ARGS=%$ ++ ++:execute ++@rem Setup the command line ++ ++set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar ++ ++@rem Execute Gradle ++"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% ++ ++:end ++@rem End local scope for the variables with windows NT shell ++if "%ERRORLEVEL%"=="0" goto mainEnd ++ ++:fail ++rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of ++rem the _cmd.exe /c_ return code! ++if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 ++exit /b 1 ++ ++:mainEnd ++if "%OS%"=="Windows_NT" endlocal ++ ++:omega +diff --git a/settings.gradle b/settings.gradle +new file mode 100644 +index 0000000..7dfd6c3 +--- /dev/null ++++ b/settings.gradle +@@ -0,0 +1 @@ ++rootProject.name = "fernflower" +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0002-Output-generic-parametrs-for-anonymous-classes.patch b/FernFlower-Patches/0002-Output-generic-parametrs-for-anonymous-classes.patch new file mode 100644 index 0000000..0492e45 --- /dev/null +++ b/FernFlower-Patches/0002-Output-generic-parametrs-for-anonymous-classes.patch @@ -0,0 +1,48 @@ +From 87ede1c33768fd77ab480c2b60cea3b23de9f754 Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sat, 1 Aug 2015 13:45:25 -0700 +Subject: [PATCH 002/122] Output generic parametrs for anonymous classes. + +--- + .../modules/decompiler/exps/NewExprent.java | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +index b5ecd9e..24facc9 100644 +--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java ++++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +@@ -26,7 +26,10 @@ import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; + import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; + import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; + import org.jetbrains.java.decompiler.struct.StructClass; ++import org.jetbrains.java.decompiler.struct.attr.StructGenericSignatureAttribute; + import org.jetbrains.java.decompiler.struct.gen.VarType; ++import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor; ++import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; + import org.jetbrains.java.decompiler.util.InterpreterUtil; + import org.jetbrains.java.decompiler.util.ListStack; + +@@ -234,6 +237,20 @@ public class NewExprent extends Exprent { + typename = typename.substring(typename.lastIndexOf('.') + 1); + } + } ++ ++ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { ++ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)child.getWrapper().getClassStruct().getAttributes().getWithKey("Signature"); ++ if (attr != null) { ++ GenericClassDescriptor descriptor = GenericMain.parseClassSignature(attr.getSignature()); ++ // Anon classes can only be a child to one type. So either the first interface or the super class ++ if (descriptor.superinterfaces.size() > 0) { ++ typename = GenericMain.getGenericCastTypeName(descriptor.superinterfaces.get(0)); ++ } ++ else { ++ typename = GenericMain.getGenericCastTypeName(descriptor.superclass); ++ } ++ } ++ } + buf.prepend("new " + typename); + + if (enclosing != null) { +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0002-Test-Framework-upgrades.patch b/FernFlower-Patches/0002-Test-Framework-upgrades.patch deleted file mode 100644 index b22363a..0000000 --- a/FernFlower-Patches/0002-Test-Framework-upgrades.patch +++ /dev/null @@ -1,283 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Tue, 11 Apr 2017 23:18:58 -0700 -Subject: [PATCH] Test Framework upgrades - - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -index bb303e84f33161a4b4fd40a73aa48d29981d9ef2..cc1f537e71af0748b7b97d7d8489198e2a677cc9 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -@@ -110,6 +110,10 @@ public class Exprent implements IMatchable { - throw new RuntimeException("not implemented"); - } - -+ public TextBuffer toJava() { -+ return toJava(0, BytecodeMappingTracer.DUMMY); -+ } -+ - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - throw new RuntimeException("not implemented"); - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -index 18a820c7d4723b35f09fa4c841e8399a547acdc7..224d3636f7c9d502cc65c122f542324c1ba7028a 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -@@ -430,6 +430,10 @@ public abstract class Statement implements IMatchable { - return false; - } - -+ public TextBuffer toJava() { -+ return toJava(0, BytecodeMappingTracer.DUMMY); -+ } -+ - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - throw new RuntimeException("not implemented"); - } -diff --git a/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java b/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java -index f8c2afde883ffe8c681d4e63821991ae82fccdaa..49cbf8407df5952f3da980e6a10f284ff2f27817 100644 ---- a/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java -+++ b/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java -@@ -28,6 +28,7 @@ public class DecompilerTestFixture { - private Path tempDir; - private Path targetDir; - private TestConsoleDecompiler decompiler; -+ private boolean cleanup = true; - - public void setUp(Map customOptions) throws IOException { - testDataDir = Path.of("testData"); -@@ -56,7 +57,7 @@ public class DecompilerTestFixture { - - public void tearDown() throws IOException { - try { -- if (tempDir != null) { -+ if (tempDir != null && cleanup) { - deleteRecursively(tempDir); - } - } -@@ -81,6 +82,14 @@ public class DecompilerTestFixture { - return decompiler; - } - -+ public void setCleanup(boolean value) { -+ this.cleanup = value; -+ } -+ -+ public boolean getCleanup() { -+ return cleanup; -+ } -+ - private static boolean isTestDataDir(Path dir) { - return Files.isDirectory(dir) && Files.isDirectory(dir.resolve("classes")) && Files.isDirectory(dir.resolve("results")); - } -diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java -index fc6a4427e586f51fa0bbe43cbb206809e32dfa57..89adb4e6fca7186ae849e62b98a9253de2dd29ef 100644 ---- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java -+++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java -@@ -4,28 +4,13 @@ package org.jetbrains.java.decompiler; - import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.main.extern.ClassFormatException; - import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; --import org.junit.After; --import org.junit.Before; - import org.junit.Rule; - import org.junit.Test; - import org.junit.rules.Timeout; - --import java.io.IOException; --import java.io.UncheckedIOException; --import java.nio.file.DirectoryStream; --import java.nio.file.Files; --import java.nio.file.Path; --import java.util.ArrayList; --import java.util.List; - import java.util.Map; - --import static org.assertj.core.api.Assertions.assertThat; --import static org.jetbrains.java.decompiler.DecompilerTestFixture.assertFilesEqual; --import static org.junit.Assert.assertTrue; -- --public class SingleClassesTest { -- private DecompilerTestFixture fixture; -- -+public class SingleClassesTest extends SingleClassesTestBase { - /* - * Set individual test duration time limit to 60 seconds. - * This will help us to test bugs hanging decompiler. -@@ -33,19 +18,12 @@ public class SingleClassesTest { - @Rule - public Timeout globalTimeout = Timeout.seconds(60); - -- @Before -- public void setUp() throws IOException { -- fixture = new DecompilerTestFixture(); -- fixture.setUp(Map.of(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", -+ @Override -+ protected Map getDecompilerOptions() { -+ return Map.of(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", - IFernflowerPreferences.DUMP_ORIGINAL_LINES, "1", - IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", -- IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1")); -- } -- -- @After -- public void tearDown() throws IOException { -- fixture.tearDown(); -- fixture = null; -+ IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1"); - } - - @Test public void testPrimitiveNarrowing() { doTest("pkg/TestPrimitiveNarrowing"); } -@@ -229,49 +207,4 @@ public class SingleClassesTest { - - @Test(expected = ClassFormatException.class) - public void testUnsupportedConstantPoolEntry() { doTest("java11/TestUnsupportedConstantPoolEntry"); } -- -- private void doTest(String testFile, String... companionFiles) { -- var decompiler = fixture.getDecompiler(); -- -- var classFile = fixture.getTestDataDir().resolve("classes/" + testFile + ".class"); -- assertThat(classFile).isRegularFile(); -- for (var file : collectClasses(classFile)) { -- decompiler.addSource(file.toFile()); -- } -- -- for (String companionFile : companionFiles) { -- var companionClassFile = fixture.getTestDataDir().resolve("classes/" + companionFile + ".class"); -- assertThat(companionClassFile).isRegularFile(); -- for (var file : collectClasses(companionClassFile)) { -- decompiler.addSource(file.toFile()); -- } -- } -- -- decompiler.decompileContext(); -- -- var decompiledFile = fixture.getTargetDir().resolve(classFile.getFileName().toString().replace(".class", ".java")); -- assertThat(decompiledFile).isRegularFile(); -- assertTrue(Files.isRegularFile(decompiledFile)); -- var referenceFile = fixture.getTestDataDir().resolve("results/" + classFile.getFileName().toString().replace(".class", ".dec")); -- assertThat(referenceFile).isRegularFile(); -- assertFilesEqual(referenceFile, decompiledFile); -- } -- -- private static List collectClasses(Path classFile) { -- var files = new ArrayList(); -- files.add(classFile); -- -- var parent = classFile.getParent(); -- if (parent != null) { -- var glob = classFile.getFileName().toString().replace(".class", "$*.class"); -- try (DirectoryStream inner = Files.newDirectoryStream(parent, glob)) { -- inner.forEach(files::add); -- } -- catch (IOException e) { -- throw new UncheckedIOException(e); -- } -- } -- -- return files; -- } - } -diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java -new file mode 100644 -index 0000000000000000000000000000000000000000..05df2e2f7842eb444a1015c69894efc69416f55a ---- /dev/null -+++ b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java -@@ -0,0 +1,96 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler; -+ -+import org.junit.After; -+import org.junit.Before; -+import java.io.IOException; -+import java.io.UncheckedIOException; -+import java.nio.file.DirectoryStream; -+import java.nio.file.Files; -+import java.nio.file.Path; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.Map; -+ -+import static org.assertj.core.api.Assertions.assertThat; -+import static org.jetbrains.java.decompiler.DecompilerTestFixture.assertFilesEqual; -+import static org.junit.Assert.assertTrue; -+ -+public class SingleClassesTestBase { -+ protected DecompilerTestFixture fixture; -+ -+ protected Map getDecompilerOptions() { -+ return Map.of(); -+ } -+ -+ @Before -+ public void setUp() throws IOException { -+ fixture = new DecompilerTestFixture(); -+ fixture.setUp(getDecompilerOptions()); -+ } -+ -+ @After -+ public void tearDown() throws IOException { -+ fixture.tearDown(); -+ fixture = null; -+ } -+ -+ protected void doTest(String testFile, String... companionFiles) { -+ var decompiler = fixture.getDecompiler(); -+ -+ var classFile = fixture.getTestDataDir().resolve("classes/" + testFile + ".class"); -+ assertThat(classFile).isRegularFile(); -+ for (var file : collectClasses(classFile)) { -+ decompiler.addSource(file.toFile()); -+ } -+ -+ for (String companionFile : companionFiles) { -+ var companionClassFile = fixture.getTestDataDir().resolve("classes/" + companionFile + ".class"); -+ assertThat(companionClassFile).isRegularFile(); -+ for (var file : collectClasses(companionClassFile)) { -+ decompiler.addSource(file.toFile()); -+ } -+ } -+ -+ decompiler.decompileContext(); -+ -+ var decompiledFile = fixture.getTargetDir().resolve(classFile.getFileName().toString().replace(".class", ".java")); -+ assertThat(decompiledFile).isRegularFile(); -+ assertTrue(Files.isRegularFile(decompiledFile)); -+ var referenceFile = fixture.getTestDataDir().resolve("results/" + classFile.getFileName().toString().replace(".class", ".dec")); -+ assertThat(referenceFile).isRegularFile(); -+ assertFilesEqual(referenceFile, decompiledFile); -+ } -+ -+ private static List collectClasses(Path classFile) { -+ var files = new ArrayList(); -+ files.add(classFile); -+ -+ var parent = classFile.getParent(); -+ if (parent != null) { -+ var glob = classFile.getFileName().toString().replace(".class", "$*.class"); -+ try (DirectoryStream inner = Files.newDirectoryStream(parent, glob)) { -+ inner.forEach(files::add); -+ } -+ catch (IOException e) { -+ throw new UncheckedIOException(e); -+ } -+ } -+ -+ return files; -+ } -+} -\ No newline at end of file diff --git a/FernFlower-Patches/0003-Fix-initializers-for-anon-and-synthetic-classes.patch b/FernFlower-Patches/0003-Fix-initializers-for-anon-and-synthetic-classes.patch deleted file mode 100644 index 29e15fd..0000000 --- a/FernFlower-Patches/0003-Fix-initializers-for-anon-and-synthetic-classes.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Wed, 12 Apr 2017 13:21:00 -0700 -Subject: [PATCH] Fix initializers for anon and synthetic classes - - -diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java -index 31f14c60939faaf73e8b971cb64c81b49decda81..9b4e9fb3ab0a2f54c124c8a4c3943e6d7a5d01d2 100644 ---- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java -+++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java -@@ -46,6 +46,7 @@ public class ClassWriter { - StructClass cl = wrapper.getClassStruct(); - - InitializerProcessor.extractInitializers(wrapper); -+ InitializerProcessor.hideInitalizers(wrapper); - - if (node.type == ClassNode.CLASS_ROOT && - !cl.isVersion5() && -diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index b09304aac7771bda2dcec3ef535f9035904f3c94..8dc45a1de093a5e81ef74e034faf2041618ced99 100644 ---- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -@@ -88,6 +88,31 @@ public class ClassesProcessor implements CodeConstants { - rec.type = entry.simpleNameIdx == 0 ? ClassNode.CLASS_ANONYMOUS : entry.outerNameIdx == 0 ? ClassNode.CLASS_LOCAL : ClassNode.CLASS_MEMBER; - rec.accessFlags = entry.accessFlags; - -+ // nested class type -+ if (entry.innerName != null) { -+ if (entry.simpleName == null) { -+ rec.type = ClassNode.CLASS_ANONYMOUS; -+ } -+ else { -+ StructClass in = context.getClass(entry.innerName); -+ if (in == null) { // A referenced library that was not added to the context, make assumptions -+ rec.type = ClassNode.CLASS_MEMBER; -+ } -+ else { -+ StructEnclosingMethodAttribute attr = in.getAttribute(StructGeneralAttribute.ATTRIBUTE_ENCLOSING_METHOD); -+ if (attr != null && attr.getMethodName() != null) { -+ rec.type = ClassNode.CLASS_LOCAL; -+ } -+ else { -+ rec.type = ClassNode.CLASS_MEMBER; -+ } -+ } -+ } -+ } -+ else { // This should never happen as inner_class and outer_class are NOT optional, make assumptions -+ rec.type = ClassNode.CLASS_MEMBER; -+ } -+ - // enclosing class - String enclClassName = entry.outerNameIdx != 0 ? entry.enclosingName : cl.qualifiedName; - if (enclClassName == null || innerName.equals(enclClassName)) { -diff --git a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java -index 7abfd011cee7c1c14a1418f826a39403f75a62db..b44a78019f0717213822ef5572c5d7ecde6d4ee3 100644 ---- a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java -@@ -13,6 +13,9 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.Statements; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; - import org.jetbrains.java.decompiler.struct.StructClass; - import org.jetbrains.java.decompiler.struct.StructField; -+import org.jetbrains.java.decompiler.struct.StructMethod; -+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.util.InterpreterUtil; - - import java.util.ArrayList; -@@ -90,8 +93,52 @@ public final class InitializerProcessor { - Exprent exprent = firstData.getExprents().get(0); - if (exprent.type == Exprent.EXPRENT_INVOCATION) { - InvocationExprent invExpr = (InvocationExprent)exprent; -- if (Statements.isInvocationInitConstructor(invExpr, method, wrapper, false) && invExpr.getParameters().isEmpty()) { -- firstData.getExprents().remove(0); -+ if (Statements.isInvocationInitConstructor(invExpr, method, wrapper, false)) { -+ List mask = ExprUtil.getSyntheticParametersMask(invExpr.getClassName(), invExpr.getStringDescriptor(), invExpr.getParameters().size()); -+ boolean hideSuper = true; -+ -+ //searching for non-synthetic params -+ for (int i = 0; i < invExpr.getDescriptor().params.length; ++i) { -+ if (mask != null && mask.get(i) != null) { -+ continue; -+ } -+ VarType type = invExpr.getDescriptor().params[i]; -+ if (type.getType() == CodeConstants.TYPE_OBJECT) { -+ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(type.getValue()); -+ if (node != null && (node.type == ClassNode.CLASS_ANONYMOUS || (node.access & CodeConstants.ACC_SYNTHETIC) != 0)) { -+ break; // Should be last -+ } -+ } -+ hideSuper = false; // found non-synthetic param so we keep the call -+ break; -+ } -+ -+ if (hideSuper) { -+ firstData.getExprents().remove(0); -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ public static void hideInitalizers(ClassWrapper wrapper) { -+ // hide initializers with anon class arguments -+ for (MethodWrapper method : wrapper.getMethods()) { -+ StructMethod mt = method.methodStruct; -+ String name = mt.getName(); -+ String desc = mt.getDescriptor(); -+ -+ if (mt.isSynthetic() && CodeConstants.INIT_NAME.equals(name)) { -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(desc); -+ if (md.params.length > 0) { -+ VarType type = md.params[md.params.length - 1]; -+ if (type.getType() == CodeConstants.TYPE_OBJECT) { -+ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(type.getValue()); -+ if (node != null && (node.type == ClassNode.CLASS_ANONYMOUS) || (node.access & CodeConstants.ACC_SYNTHETIC) != 0) { -+ //TODO: Verify that the body is JUST a this([args]) call? -+ wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(name, desc)); -+ } - } - } - } diff --git a/FernFlower-Patches/0003-Loosen-up-restrictions-on-field-initalizers-allowing.patch b/FernFlower-Patches/0003-Loosen-up-restrictions-on-field-initalizers-allowing.patch new file mode 100644 index 0000000..33d30c6 --- /dev/null +++ b/FernFlower-Patches/0003-Loosen-up-restrictions-on-field-initalizers-allowing.patch @@ -0,0 +1,116 @@ +From be53afc282317c377cf92433cf40b01dce77af77 Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sat, 1 Aug 2015 15:10:28 -0700 +Subject: [PATCH 003/122] Loosen up restrictions on field initalizers allowing + for some to be moved out of the and functions. + +--- + .../decompiler/main/InitializerProcessor.java | 37 ++++++++++++------- + 1 file changed, 23 insertions(+), 14 deletions(-) + +diff --git a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +index d9a0a3d..d916b19 100644 +--- a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java ++++ b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +@@ -29,7 +29,10 @@ import org.jetbrains.java.decompiler.struct.StructField; + import org.jetbrains.java.decompiler.util.InterpreterUtil; + + import java.util.ArrayList; ++import java.util.HashSet; ++import java.util.Iterator; + import java.util.List; ++import java.util.Set; + + + public class InitializerProcessor { +@@ -124,13 +127,13 @@ public class InitializerProcessor { + + RootStatement root = meth.root; + StructClass cl = wrapper.getClassStruct(); ++ Set whitelist = new HashSet(); + + Statement firstdata = findFirstData(root); + if (firstdata != null) { +- while (!firstdata.getExprents().isEmpty()) { +- Exprent exprent = firstdata.getExprents().get(0); +- +- boolean found = false; ++ Iterator itr = firstdata.getExprents().iterator(); ++ while (itr.hasNext()) { ++ Exprent exprent = itr.next(); + + if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { + AssignmentExprent asexpr = (AssignmentExprent)exprent; +@@ -139,22 +142,18 @@ public class InitializerProcessor { + if (fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) && + cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) { + +- if (isExprentIndependent(asexpr.getRight(), meth)) { ++ if (isExprentIndependent(asexpr.getRight(), meth, cl, whitelist)) { + + String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString); + if (!wrapper.getStaticFieldInitializers().containsKey(keyField)) { + wrapper.getStaticFieldInitializers().addWithKey(asexpr.getRight(), keyField); +- firstdata.getExprents().remove(0); +- found = true; ++ whitelist.add(keyField); ++ itr.remove(); + } + } + } + } + } +- +- if (!found) { +- break; +- } + } + } + } +@@ -191,6 +190,8 @@ public class InitializerProcessor { + return; + } + ++ Set whitelist = new HashSet(); ++ + while (true) { + + String fieldWithDescr = null; +@@ -216,7 +217,7 @@ public class InitializerProcessor { + cl.hasField(fexpr.getName(), fexpr + .getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass. + +- if (isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i))) { ++ if (isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i), cl, whitelist)) { + String fieldKey = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString); + if (fieldWithDescr == null) { + fieldWithDescr = fieldKey; +@@ -252,7 +253,7 @@ public class InitializerProcessor { + } + } + +- private static boolean isExprentIndependent(Exprent exprent, MethodWrapper meth) { ++ private static boolean isExprentIndependent(Exprent exprent, MethodWrapper meth, StructClass cl, Set whitelist) { + + List lst = exprent.getAllExprents(true); + lst.add(exprent); +@@ -270,7 +271,15 @@ public class InitializerProcessor { + } + break; + case Exprent.EXPRENT_FIELD: +- return false; ++ FieldExprent fexpr = (FieldExprent)expr; ++ if (cl.qualifiedName.equals(fexpr.getClassname())) { ++ if (!whitelist.contains(InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString))) { ++ return false; ++ } ++ } ++ else if (!fexpr.isStatic()) { ++ return false; ++ } + } + } + +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0004-Fix-output-discrepancies-to-produce-stable-output.patch b/FernFlower-Patches/0004-Fix-output-discrepancies-to-produce-stable-output.patch deleted file mode 100644 index 73c6a48..0000000 --- a/FernFlower-Patches/0004-Fix-output-discrepancies-to-produce-stable-output.patch +++ /dev/null @@ -1,1373 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Wed, 12 Apr 2017 10:08:10 -0700 -Subject: [PATCH] Fix output discrepancies to produce stable output - -Running JVM and timestamp result in output varying between -environments and runs. - -diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index 8dc45a1de093a5e81ef74e034faf2041618ced99..8173ecd04da97e5e9a8f5f9a2e309726439697e0 100644 ---- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -@@ -249,6 +249,7 @@ public class ClassesProcessor implements CodeConstants { - stack.add(nestedClass); - } - } -+ Collections.sort(superNode.nested); - } - } - } -@@ -451,7 +452,7 @@ public class ClassesProcessor implements CodeConstants { - } - - -- public static class ClassNode { -+ public static class ClassNode implements Comparable { - public static final int CLASS_ROOT = 0; - public static final int CLASS_MEMBER = 1; - public static final int CLASS_ANONYMOUS = 2; -@@ -542,6 +543,12 @@ public class ClassesProcessor implements CodeConstants { - isNonSealed = nonSealed; - } - -+ @Override -+ public int compareTo(ClassNode o) { -+ //TODO: Take line numbers into account? -+ return this.classStruct.qualifiedName.compareTo(o.classStruct.qualifiedName); -+ } -+ - public static class LambdaInformation { - public String method_name; - public String method_descriptor; -diff --git a/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java b/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java -index 75d4d0937f1e39fe630b1318a4ad531de7fbd644..d0ae9a7c3b20de44cb202390cc0dfd4d690fee64 100644 ---- a/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java -+++ b/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java -@@ -11,7 +11,7 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil; - import java.io.*; - import java.nio.charset.StandardCharsets; - import java.util.*; --import java.util.jar.JarOutputStream; -+import java.util.jar.JarFile; - import java.util.jar.Manifest; - import java.util.zip.ZipEntry; - import java.util.zip.ZipFile; -@@ -189,7 +189,14 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver { - } - - FileOutputStream fileStream = new FileOutputStream(file); -- ZipOutputStream zipStream = manifest != null ? new JarOutputStream(fileStream, manifest) : new ZipOutputStream(fileStream); -+ ZipOutputStream zipStream = new ZipOutputStream(fileStream); -+ if (manifest != null) { -+ final ZipEntry manifestEntry = new ZipEntry(JarFile.MANIFEST_NAME); -+ manifestEntry.setTime(STABLE_ZIP_TIMESTAMP); -+ zipStream.putNextEntry(manifestEntry); -+ manifest.write(zipStream); -+ zipStream.closeEntry(); -+ } - mapArchiveStreams.put(file.getPath(), zipStream); - } - catch (IOException ex) { -@@ -215,7 +222,9 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver { - if (entry != null) { - try (InputStream in = srcArchive.getInputStream(entry)) { - ZipOutputStream out = mapArchiveStreams.get(file); -- out.putNextEntry(new ZipEntry(entryName)); -+ final ZipEntry newEntry = new ZipEntry(entryName); -+ newEntry.setTime(entry.getTime()); -+ out.putNextEntry(newEntry); - InterpreterUtil.copyStream(in, out); - } - } -@@ -236,7 +245,9 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver { - - try { - ZipOutputStream out = mapArchiveStreams.get(file); -- out.putNextEntry(new ZipEntry(entryName)); -+ ZipEntry entry = new ZipEntry(entryName); -+ entry.setTime(STABLE_ZIP_TIMESTAMP); -+ out.putNextEntry(entry); - if (content != null) { - out.write(content.getBytes(StandardCharsets.UTF_8)); - } -diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -index 5448e7900953da79b2bc01f99fd7e8f3080148e7..b509376a6dbc3780f7c14c631bf51b7fc24aa50d 100644 ---- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -+++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -@@ -35,6 +35,8 @@ public interface IFernflowerPreferences { - String IGNORE_INVALID_BYTECODE = "iib"; - String VERIFY_ANONYMOUS_CLASSES = "vac"; - -+ String STANDARDIZE_FLOATING_POINT_NUMBERS = "sfn"; -+ - String LOG_LEVEL = "log"; - String MAX_PROCESSING_METHOD = "mpm"; - String RENAME_ENTITIES = "ren"; -@@ -81,6 +83,8 @@ public interface IFernflowerPreferences { - defaults.put(IGNORE_INVALID_BYTECODE, "0"); - defaults.put(VERIFY_ANONYMOUS_CLASSES, "0"); - -+ defaults.put(STANDARDIZE_FLOATING_POINT_NUMBERS, "1"); -+ - defaults.put(LOG_LEVEL, IFernflowerLogger.Severity.INFO.name()); - defaults.put(MAX_PROCESSING_METHOD, "0"); - defaults.put(RENAME_ENTITIES, "0"); -diff --git a/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java b/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java -index fad1ddcfb9d2e43720b4cd3acaa165ba86e94892..cf03900654e427bd435ba6dc2d5a0cec8c8708e4 100644 ---- a/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java -+++ b/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java -@@ -4,6 +4,8 @@ package org.jetbrains.java.decompiler.main.extern; - import java.util.jar.Manifest; - - public interface IResultSaver { -+ long STABLE_ZIP_TIMESTAMP = 0x386D4380; // 01/01/2000 00:00:00 java 8 breaks when using 0. -+ - void saveFolder(String path); - - void copyFile(String source, String path, String entryName); -diff --git a/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java -index 05e6e2d720aa5812ef12c4741eab06b8ea477e0f..f9c8c6a0334512699c545c881207194745427c96 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java -@@ -19,6 +19,7 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil; - - import java.io.IOException; - import java.util.BitSet; -+import java.util.Collections; - import java.util.HashMap; - import java.util.List; - import java.util.Map; -@@ -110,6 +111,8 @@ public class LambdaProcessor { - mt.releaseResources(); - } - -+ Collections.sort(node.nested); -+ - // build class hierarchy on lambda - for (ClassNode nd : node.nested) { - if (nd.type == ClassNode.CLASS_LAMBDA) { -@@ -119,6 +122,7 @@ public class LambdaProcessor { - - parent_class.nested.add(nd); - nd.parent = parent_class; -+ Collections.sort(parent_class.nested); - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index da1fc15420faf03e1afbf74c39f888a6cb9c9ce8..6e5fe5474d6878d789758a5e7791b03e5da6685e 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -@@ -218,6 +218,7 @@ public class NestedClassProcessor { - if (setEnclosing.contains(node.classStruct.qualifiedName)) { - node.nested.add(child); - child.parent = node; -+ Collections.sort(node.nested); - - return true; - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java -index 868955437f5c05d8b011671089de24aa7d5ab8cc..277e792a2856334970bafe0661582a8c8d09ad5a 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java -@@ -194,7 +194,7 @@ public final class DomHelper { - - RootStatement root = graphToStatement(graph); - -- if (!processStatement(root, new HashMap<>())) { -+ if (!processStatement(root, new LinkedHashMap<>())) { - - // try { - // DotExporter.toDotFile(root.getFirst().getStats().get(13), new File("c:\\Temp\\stat1.dot")); -@@ -204,7 +204,7 @@ public final class DomHelper { - throw new RuntimeException("parsing failure!"); - } - -- LabelHelper.lowContinueLabels(root, new HashSet<>()); -+ LabelHelper.lowContinueLabels(root, new LinkedHashSet<>()); - - SequenceHelper.condenseSequences(root); - root.buildMonitorFlags(); -@@ -452,11 +452,11 @@ public final class DomHelper { - - boolean same = (post == head); - -- HashSet setNodes = new HashSet<>(); -+ HashSet setNodes = new LinkedHashSet<>(); - HashSet setPreds = new HashSet<>(); - - // collect statement nodes -- HashSet setHandlers = new HashSet<>(); -+ HashSet setHandlers = new LinkedHashSet<>(); - setHandlers.add(head); - while (true) { - -@@ -601,7 +601,7 @@ public final class DomHelper { - set.removeAll(setOldNodes); - - if (setOldNodes.contains(key)) { -- mapExtPost.computeIfAbsent(newid, k -> new HashSet<>()).addAll(set); -+ mapExtPost.computeIfAbsent(newid, k -> new LinkedHashSet<>()).addAll(set); - mapExtPost.remove(key); - } - else { -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -index cf3ce3d5c4d304c8f1ee121a9781d3238f794b91..6783382a1c199ba33df1af3477d3cf5e13230b09 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -@@ -928,6 +928,7 @@ public class ExprProcessor implements CodeConstants { - } - - TextBuffer buf = new TextBuffer(); -+ lst = Exprent.sortIndexed(lst); - - for (Exprent expr : lst) { - if (buf.length() > 0 && expr.type == Exprent.EXPRENT_VAR && ((VarExprent)expr).isClassDef()) { -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java -index 2770c678a4572cd95bbb0d7f98fadb4bb62fcbd8..878c12b061975d4060b8a44abffa3d60d35d17a3 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java -@@ -453,9 +453,16 @@ public class FinallyProcessor { - // `throw` in the `try` body will point directly to the dummy exit, so remove it - startBlocks.remove(graph.getLast()); - startBlocks.removeAll(tryBlocks); -+ List starts = new ArrayList<>(startBlocks); -+ Collections.sort(starts, new Comparator() { -+ @Override -+ public int compare(BasicBlock o1, BasicBlock o2) { -+ return o2.id - o1.id; -+ } -+ }); - - List areas = new ArrayList<>(); -- for (BasicBlock start : startBlocks) { -+ for (BasicBlock start : starts) { - Area arr = compareSubGraphsEx(graph, start, catchBlocks, first, finallyType, mapLast, skippedFirst); - if (arr == null) { - return false; -@@ -468,8 +475,12 @@ public class FinallyProcessor { - deleteArea(graph, area); - } - -+ List> lasts = new ArrayList<>(mapLast.entrySet()); -+ // We must sort here to prevent decompile differences deriving from hash maps. -+ lasts.sort(Comparator.comparingInt(o -> o.getKey().id)); -+ - // INFO: Empty basic blocks may remain in the graph! -- for (Entry entry : mapLast.entrySet()) { -+ for (Entry entry : lasts) { - BasicBlock last = entry.getKey(); - - if (entry.getValue()) { -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java -index df41b33643bd48f0f5549efe0931eb489dac21c9..1416640aedb91596be42c94697c3f74a25c1229d 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java -@@ -23,7 +23,7 @@ public final class LabelHelper { - - liftClosures(root); - -- lowContinueLabels(root, new HashSet<>()); -+ lowContinueLabels(root, new LinkedHashSet<>()); - - lowClosures(root); - } -@@ -120,7 +120,7 @@ public final class LabelHelper { - lowContinueLabels(st, edges); - } - else { -- lowContinueLabels(st, new HashSet<>()); -+ lowContinueLabels(st, new LinkedHashSet<>()); - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java -index 09e36dc4686d5e445a48325295ace392a79182f7..da65e74c53d2dc8f0e5f5ab538fe7b9defc5b135 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java -@@ -14,10 +14,10 @@ public class DominatorTreeExceptionFilter { - private final Statement statement; - - // idom, nodes -- private final Map> mapTreeBranches = new HashMap<>(); -+ private final Map> mapTreeBranches = new LinkedHashMap<>(); - - // handler, range nodes -- private final Map> mapExceptionRanges = new HashMap<>(); -+ private final Map> mapExceptionRanges = new LinkedHashMap<>(); - - // handler, head dom - private Map mapExceptionDoms = new HashMap<>(); -@@ -67,7 +67,7 @@ public class DominatorTreeExceptionFilter { - for (int index = lstKeys.size() - 1; index >= 0; index--) { - Integer key = lstKeys.get(index); - Integer idom = orderedIDoms.get(index); -- mapTreeBranches.computeIfAbsent(idom, k -> new HashSet<>()).add(key); -+ mapTreeBranches.computeIfAbsent(idom, k -> new LinkedHashSet<>()).add(key); - } - - Integer firstid = statement.getFirst().id; -@@ -79,7 +79,7 @@ public class DominatorTreeExceptionFilter { - List lstPreds = stat.getNeighbours(EdgeType.EXCEPTION, EdgeDirection.BACKWARD); - if (!lstPreds.isEmpty()) { - -- Set set = new HashSet<>(); -+ Set set = new LinkedHashSet<>(); - - for (Statement st : lstPreds) { - set.add(st.id); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java -index 82ae0a25a20d2727f611d359e699d6666d1e0ae4..a86f0d2887c6c19cb1d911ec43830eb69f8aaada 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java -@@ -14,9 +14,9 @@ public class FastExtendedPostdominanceHelper { - - private List lstReversePostOrderList; - -- private HashMap> mapSupportPoints = new HashMap<>(); -+ private HashMap> mapSupportPoints = new LinkedHashMap<>(); - -- private final HashMap> mapExtPostdominators = new HashMap<>(); -+ private final HashMap> mapExtPostdominators = new LinkedHashMap<>(); - - private Statement statement; - -@@ -26,7 +26,7 @@ public class FastExtendedPostdominanceHelper { - - this.statement = statement; - -- HashSet set = new HashSet<>(); -+ HashSet set = new LinkedHashSet<>(); - for (Statement st : statement.getStats()) { - set.add(st.id); - } -@@ -54,7 +54,9 @@ public class FastExtendedPostdominanceHelper { - Set>> entries = mapExtPostdominators.entrySet(); - HashMap> res = new HashMap<>(entries.size()); - for (Entry> entry : entries) { -- res.put(entry.getKey(), entry.getValue().toPlainSet()); -+ List lst = new ArrayList<>(entry.getValue().toPlainSet()); -+ Collections.sort(lst); // Order Matters! -+ res.put(entry.getKey(), new LinkedHashSet<>(lst)); - } - - return res; -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index 743074d1b43f6b331cef74c94bb11a49fefbfb61..623d59228cc526cca3bbd52e95e4d493c689f133 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -@@ -216,7 +216,7 @@ public class ConstExprent extends Exprent { - else if (floatVal == Float.NEGATIVE_INFINITY) { - yield new TextBuffer("-1.0F / 0.0F"); - } -- yield new TextBuffer(value.toString()).append('F'); -+ yield new TextBuffer(trimFloat(Float.toString(floatVal), floatVal)).append('F'); - } - case CodeConstants.TYPE_DOUBLE -> { - double doubleVal = (Double)value; -@@ -247,15 +247,15 @@ public class ConstExprent extends Exprent { - } - } - else if (Double.isNaN(doubleVal)) { -- yield new TextBuffer("0.0 / 0.0"); -+ yield new TextBuffer("0.0D / 0.0D"); - } - else if (doubleVal == Double.POSITIVE_INFINITY) { -- yield new TextBuffer("1.0 / 0.0"); -+ yield new TextBuffer("1.0D / 0.0D"); - } - else if (doubleVal == Double.NEGATIVE_INFINITY) { -- yield new TextBuffer("-1.0 / 0.0"); -+ yield new TextBuffer("-1.0D / 0.0D"); - } -- yield new TextBuffer(value.toString()); -+ yield new TextBuffer(trimDouble(Double.toString(doubleVal), doubleVal)).append('D'); - } - case CodeConstants.TYPE_NULL -> new TextBuffer("null"); - case CodeConstants.TYPE_OBJECT -> { -@@ -273,6 +273,92 @@ public class ConstExprent extends Exprent { - }; - } - -+ // Different JVM implementations/version display Floats and Doubles with different String representations -+ // for the same thing. This trims them all down to only the necessary amount. -+ private static String trimFloat(String value, float start) { -+ // Includes NaN and simple numbers -+ if (value.length() <= 3 || !DecompilerContext.getOption(IFernflowerPreferences.STANDARDIZE_FLOATING_POINT_NUMBERS)) -+ return value; -+ -+ String exp = ""; -+ int eIdx = value.indexOf('E'); -+ if (eIdx != -1) { -+ exp = value.substring(eIdx); -+ value = value.substring(0, eIdx); -+ } -+ -+ // Cut off digits that don't affect the value -+ String temp = value; -+ int dotIdx = value.indexOf('.'); -+ do { -+ value = temp; -+ temp = value.substring(0, value.length() - 1); -+ } while (!temp.isEmpty() && !"-".equals(temp) && Float.parseFloat(temp + exp) == start); -+ -+ if (dotIdx != -1 && value.indexOf('.') == -1) { -+ value += ".0"; -+ } else if (dotIdx != -1) { -+ String integer = value.substring(0, dotIdx); -+ String decimal = value.substring(dotIdx + 1); -+ -+ String rounded = (Integer.parseInt(integer) + 1) + ".0" + exp; -+ if (Float.parseFloat(rounded) == start) -+ return rounded; -+ -+ long decimalVal = 1; -+ for (int i = 0; i < decimal.length() - 1; i++) { -+ decimalVal = (decimalVal - 1) * 10 + decimal.charAt(i) - '0' + 1; -+ rounded = integer + '.' + decimalVal + exp; -+ if (Float.parseFloat(rounded) == start) -+ return rounded; -+ } -+ } -+ -+ return value + exp; -+ } -+ -+ private static String trimDouble(String value, double start) { -+ // Includes NaN and simple numbers -+ if (value.length() <= 3 || !DecompilerContext.getOption(IFernflowerPreferences.STANDARDIZE_FLOATING_POINT_NUMBERS)) -+ return value; -+ -+ String exp = ""; -+ int eIdx = value.indexOf('E'); -+ if (eIdx != -1) { -+ exp = value.substring(eIdx); -+ value = value.substring(0, eIdx); -+ } -+ -+ // Cut off digits that don't affect the value -+ String temp = value; -+ int dotIdx = value.indexOf('.'); -+ do { -+ value = temp; -+ temp = value.substring(0, value.length() - 1); -+ } while (!temp.isEmpty() && !"-".equals(temp) && Double.parseDouble(temp + exp) == start); -+ -+ if (dotIdx != -1 && value.indexOf('.') == -1) { -+ value += ".0"; -+ } else if (dotIdx != -1) { -+ String integer = value.substring(0, dotIdx); -+ String decimal = value.substring(dotIdx + 1); -+ -+ String rounded = (Long.parseLong(integer) + 1) + ".0" + exp; -+ if (Double.parseDouble(rounded) == start) -+ return rounded; -+ -+ long decimalVal = 1; -+ for (int i = 0; i < decimal.length() - 1; i++) { -+ decimalVal = (decimalVal - 1) * 10 + decimal.charAt(i) - '0' + 1; -+ rounded = integer + '.' + decimalVal + exp; -+ if (Double.parseDouble(rounded) == start) -+ return rounded; -+ } -+ } -+ -+ return value + exp; -+ } -+ - private boolean inConstantVariable(String classSignature, String variableName) { - ClassesProcessor.ClassNode node = (ClassesProcessor.ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); - return node.classStruct.qualifiedName.equals(classSignature) && -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -index cc1f537e71af0748b7b97d7d8489198e2a677cc9..9b1b3de632a63bbba1f5f7a99d5f75bf537bd171 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -@@ -15,7 +15,10 @@ import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue; - -+import java.util.ArrayList; - import java.util.Collection; -+import java.util.Collections; -+import java.util.Comparator; - import java.util.HashSet; - import java.util.List; - import java.util.Map.Entry; -@@ -131,6 +134,39 @@ public class Exprent implements IMatchable { - } - } - -+ public static List sortIndexed(List lst) { -+ List ret = new ArrayList<>(); -+ List defs = new ArrayList<>(); -+ -+ Comparator comp = new Comparator<>() { -+ @Override -+ public int compare(VarExprent o1, VarExprent o2) { -+ return o1.getIndex() - o2.getIndex(); -+ } -+ }; -+ -+ for (Exprent exp : lst) { -+ boolean isDef = exp instanceof VarExprent && ((VarExprent)exp).isDefinition(); -+ if (!isDef) { -+ if (defs.size() > 0) { -+ Collections.sort(defs, comp); -+ ret.addAll(defs); -+ defs.clear(); -+ } -+ ret.add(exp); -+ } -+ else { -+ defs.add((VarExprent)exp); -+ } -+ } -+ -+ if (defs.size() > 0) { -+ Collections.sort(defs, comp); -+ ret.addAll(defs); -+ } -+ return ret; -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java -index 3991c5131e1b49cd7ee25626aa64ad3999766ce5..70b053d4138127c772f72eca7a54a1b8b3098cbf 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java -@@ -22,6 +22,7 @@ import org.jetbrains.java.decompiler.util.SFormsFastMapDirect; - import java.util.HashMap; - import java.util.HashSet; - import java.util.List; -+import java.util.ArrayList; - import java.util.Map.Entry; - import java.util.Objects; - -@@ -57,7 +58,7 @@ public class SSAConstructorSparseEx { - // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot")); - // } catch(Exception ex) {ex.printStackTrace();} - -- HashSet setInit = new HashSet<>(); -+ List setInit = new ArrayList<>(); - for (int i = 0; i < 64; i++) { - setInit.add(i); - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java -index 4d76ee298513f0989eadc2866d7a9d1f229612ef..8cd9f1de252412494f36a847167a9b74a7dd7625 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java -@@ -68,7 +68,7 @@ public class SSAUConstructorSparseEx { - FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); - DirectGraph dgraph = flatthelper.buildDirectGraph(root); - -- HashSet setInit = new HashSet<>(); -+ List setInit = new ArrayList<>(); - for (int i = 0; i < 64; i++) { - setInit.add(i); - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java -index 58f94462caa7a8212c3e9e36e343e2f4c55582f5..d355e63f8a3252bf58f0cdf18f42e6732132efef 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java -@@ -5,7 +5,8 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.util.TextBuffer; - - import java.util.Collection; --import java.util.HashSet; -+import java.util.LinkedHashSet; -+import java.util.Set; - - - public class GeneralStatement extends Statement { -@@ -25,7 +26,7 @@ public class GeneralStatement extends Statement { - first = head; - stats.addWithKey(head, head.id); - -- HashSet set = new HashSet<>(statements); -+ Set set = new LinkedHashSet<>(statements); - set.remove(head); - - for (Statement st : set) { -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java -index 133d87f45ab3b057e78589a53529821e5a6a6dea..119949c8bd35082b95cbfde2b185aa2d23034224 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java -@@ -46,7 +46,16 @@ public final class SwitchStatement extends Statement { - regularSuccessors.remove(post); - } - defaultEdge = head.getSuccessorEdges(EdgeType.DIRECT_ALL).get(0); -- for (Statement successor : regularSuccessors) { -+ -+ //We need to use set above in case we have multiple edges to the same node. But HashSets iterator is not ordered, so sort -+ List sorted = new ArrayList<>(regularSuccessors); -+ Collections.sort(sorted, new Comparator() { -+ @Override -+ public int compare(Statement o1, Statement o2) { -+ return o1.id - o2.id; -+ } -+ }); -+ for (Statement successor : sorted) { - stats.addWithKey(successor, successor.id); - } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -index 244898d5845029fb28126bd0c0365eec1c06f657..472faf9ad843f4d4bafdc2cf7753b67d8c34bddc 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -@@ -245,7 +245,10 @@ public class VarVersionsProcessor { - Map mapOriginalVarIndices = new HashMap<>(); - - // map var-version pairs on new var indexes -- for (VarVersionPair pair : new ArrayList<>(mapExprentMinTypes.keySet())) { -+ List vvps = new ArrayList<>(mapExprentMinTypes.keySet()); -+ Collections.sort(vvps, (o1, o2) -> o1.var != o2.var ? o1.var - o2.var : o1.version - o2.version); -+ -+ for (VarVersionPair pair : vvps) { - - if (pair.version >= 0) { - int newIndex = pair.version == 1 ? pair.var : counters.getCounterAndIncrement(CounterContainer.VAR_COUNTER); -diff --git a/testData/results/MoreAnnotations.dec b/testData/results/MoreAnnotations.dec -index 7ea22e010e25dae99314be45985743c85da03b33..8a16a352f46a45a57f5dd2cbb8fbd14161178022 100644 ---- a/testData/results/MoreAnnotations.dec -+++ b/testData/results/MoreAnnotations.dec -@@ -35,7 +35,7 @@ public @interface MoreAnnotations { - intArray = {1, 0, 2147483647, -2147483648}, - byteArray = {1, 0, 127, -128, -1}, - floatArray = {1.0F, 0.0F, 3.4028235E38F, 1.4E-45F, 0.0F / 0.0F, 1.0F / 0.0F, -1.0F / 0.0F}, -- doubleArray = {1.0, 0.0, 1.7976931348623157E308, 4.9E-324, 0.0 / 0.0, 1.0 / 0.0, -1.0 / 0.0}, -+ doubleArray = {1.0D, 0.0D, 1.7976931348623157E308D, 4.9E-324D, 0.0D / 0.0D, 1.0D / 0.0D, -1.0D / 0.0D}, - booleanArray = {true, false}, - shortArray = {1, 0, 32767, -32768, -1}, - longArray = {1L, 0L, 9223372036854775807L, -9223372036854775808L}, -@@ -53,7 +53,7 @@ public @interface MoreAnnotations { - - float floatValue() default 1.0F / 0.0F; - -- double doubleValue() default 0.0 / 0.0; -+ double doubleValue() default 0.0D / 0.0D; - - boolean booleanValue() default true; - -@@ -77,7 +77,7 @@ public @interface MoreAnnotations { - - float[] floatArray() default {1.0F, 0.0F, 3.4028235E38F, 1.4E-45F, 0.0F / 0.0F, 1.0F / 0.0F, -1.0F / 0.0F}; - -- double[] doubleArray() default {1.0, 0.0, 1.7976931348623157E308, 4.9E-324, 0.0 / 0.0, 1.0 / 0.0, -1.0 / 0.0}; -+ double[] doubleArray() default {1.0D, 0.0D, 1.7976931348623157E308D, 4.9E-324D, 0.0D / 0.0D, 1.0D / 0.0D, -1.0D / 0.0D}; - - boolean[] booleanArray() default {true, false}; - -@@ -95,13 +95,13 @@ public @interface MoreAnnotations { - - Class[] classArray() default {CharSequence.class, String.class, StringBuilder.class}; - -+ public @interface NestedAnnotation { -+ String value() default "MyString"; -+ } -+ - public static enum TestEnum { - FirstValue, - SecondValue; - } -- -- public @interface NestedAnnotation { -- String value() default "MyString"; -- } - } - -diff --git a/testData/results/TestAnonymousClass.dec b/testData/results/TestAnonymousClass.dec -index 9cd9f538a6a53faa511ceac028001ccef418c3aa..3ea3c7058eadc696e538c72e018bd4076b07a397 100644 ---- a/testData/results/TestAnonymousClass.dec -+++ b/testData/results/TestAnonymousClass.dec -@@ -67,15 +67,8 @@ public abstract class TestAnonymousClass { - boolean var1 = true;// 39 - }// 40 - -- static class InnerRecursive { -- InnerRecursive r; -- -- public InnerRecursive(InnerRecursive var1) { -- this.r = var1;// 105 -- }// 106 -- -- void foo() { -- }// 110 -+ interface I { -+ void foo() throws Exception; - } - - private static class Inner { -@@ -87,8 +80,15 @@ public abstract class TestAnonymousClass { - }; - } - -- interface I { -- void foo() throws Exception; -+ static class InnerRecursive { -+ TestAnonymousClass.InnerRecursive r; -+ -+ public InnerRecursive(TestAnonymousClass.InnerRecursive var1) { -+ this.r = var1;// 105 -+ }// 106 -+ -+ void foo() { -+ }// 110 - } - } - -@@ -180,24 +180,24 @@ class 'pkg/TestAnonymousClass' { - } - } - -+class 'pkg/TestAnonymousClass$Inner$1' { -+ method 'run ()V' { -+ 0 76 -+ 1 76 -+ 2 77 -+ 3 77 -+ 4 78 -+ } -+} -+ - class 'pkg/TestAnonymousClass$InnerRecursive' { - method ' (Lpkg/TestAnonymousClass$InnerRecursive;)V' { -- 6 73 -- 9 74 -+ 6 86 -+ 9 87 - } - - method 'foo ()V' { -- 0 77 -- } --} -- --class 'pkg/TestAnonymousClass$Inner$1' { -- method 'run ()V' { -- 0 83 -- 1 83 -- 2 84 -- 3 84 -- 4 85 -+ 0 90 - } - } - -@@ -223,9 +223,9 @@ Lines mapping: - 53 <-> 18 - 54 <-> 19 - 55 <-> 20 --66 <-> 84 --67 <-> 85 --68 <-> 86 -+66 <-> 77 -+67 <-> 78 -+68 <-> 79 - 75 <-> 24 - 76 <-> 25 - 77 <-> 26 -@@ -234,9 +234,9 @@ Lines mapping: - 91 <-> 37 - 92 <-> 38 - 93 <-> 39 --105 <-> 74 --106 <-> 75 --110 <-> 78 -+105 <-> 87 -+106 <-> 88 -+110 <-> 91 - Not mapped: - 18 - 104 -diff --git a/testData/results/TestAnonymousClassConstructor.dec b/testData/results/TestAnonymousClassConstructor.dec -index e4d02ffde3166e0b22f82550fa73bdea4c6d02ac..e48e5bc934ccd1ed1aedd0fcde645026bbb4e3fe 100644 ---- a/testData/results/TestAnonymousClassConstructor.dec -+++ b/testData/results/TestAnonymousClassConstructor.dec -@@ -65,16 +65,16 @@ class TestAnonymousClassConstructor { - System.out.println("n(): " + s);// 53 - }// 54 - -- static class InnerStaticPublic { -- public InnerStaticPublic(long a, int b) { -- TestAnonymousClassConstructor.n(a + "+" + b);// 100 -- }// 101 -+ class InnerPrivate { -+ private InnerPrivate(long a, int b) { -+ TestAnonymousClassConstructor.n(a + "+" + b);// 64 -+ }// 65 - } - -- static class InnerStaticPublicString { -- public InnerStaticPublicString(String s) { -- TestAnonymousClassConstructor.n(s);// 94 -- }// 95 -+ class InnerPrivateString { -+ private InnerPrivateString(String s) { -+ TestAnonymousClassConstructor.n(s);// 58 -+ }// 59 - } - - class InnerPublic { -@@ -101,16 +101,16 @@ class TestAnonymousClassConstructor { - }// 71 - } - -- class InnerPrivate { -- private InnerPrivate(long a, int b) { -- TestAnonymousClassConstructor.n(a + "+" + b);// 64 -- }// 65 -+ static class InnerStaticPublic { -+ public InnerStaticPublic(long a, int b) { -+ TestAnonymousClassConstructor.n(a + "+" + b);// 100 -+ }// 101 - } - -- class InnerPrivateString { -- private InnerPrivateString(String s) { -- TestAnonymousClassConstructor.n(s);// 58 -- }// 59 -+ static class InnerStaticPublicString { -+ public InnerStaticPublicString(String s) { -+ TestAnonymousClassConstructor.n(s);// 94 -+ }// 95 - } - } - -@@ -190,19 +190,19 @@ class 'pkg/TestAnonymousClassConstructor' { - } - } - --class 'pkg/TestAnonymousClassConstructor$InnerStaticPublic' { -- method ' (JI)V' { -- f 69 -- 18 69 -- 1b 69 -- 1e 70 -+class 'pkg/TestAnonymousClassConstructor$InnerPrivate' { -+ method ' (Lpkg/TestAnonymousClassConstructor;JI)V' { -+ 14 69 -+ 1e 69 -+ 21 69 -+ 24 70 - } - } - --class 'pkg/TestAnonymousClassConstructor$InnerStaticPublicString' { -- method ' (Ljava/lang/String;)V' { -- 5 75 -- 8 76 -+class 'pkg/TestAnonymousClassConstructor$InnerPrivateString' { -+ method ' (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' { -+ a 75 -+ d 76 - } - } - -@@ -238,19 +238,19 @@ class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivateString' { - } - } - --class 'pkg/TestAnonymousClassConstructor$InnerPrivate' { -- method ' (Lpkg/TestAnonymousClassConstructor;JI)V' { -- 14 105 -- 1e 105 -- 21 105 -- 24 106 -+class 'pkg/TestAnonymousClassConstructor$InnerStaticPublic' { -+ method ' (JI)V' { -+ f 105 -+ 18 105 -+ 1b 105 -+ 1e 106 - } - } - --class 'pkg/TestAnonymousClassConstructor$InnerPrivateString' { -- method ' (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' { -- a 111 -- d 112 -+class 'pkg/TestAnonymousClassConstructor$InnerStaticPublicString' { -+ method ' (Ljava/lang/String;)V' { -+ 5 111 -+ 8 112 - } - } - -@@ -281,10 +281,10 @@ Lines mapping: - 50 <-> 62 - 53 <-> 65 - 54 <-> 66 --58 <-> 112 --59 <-> 113 --64 <-> 106 --65 <-> 107 -+58 <-> 76 -+59 <-> 77 -+64 <-> 70 -+65 <-> 71 - 70 <-> 100 - 71 <-> 101 - 76 <-> 94 -@@ -293,10 +293,10 @@ Lines mapping: - 83 <-> 89 - 88 <-> 82 - 89 <-> 83 --94 <-> 76 --95 <-> 77 --100 <-> 70 --101 <-> 71 -+94 <-> 112 -+95 <-> 113 -+100 <-> 106 -+101 <-> 107 - Not mapped: - 57 - 63 -diff --git a/testData/results/TestClassSimpleBytecodeMapping.dec b/testData/results/TestClassSimpleBytecodeMapping.dec -index 5b26ef8b403a0cc1c2b9858ed3c9ce84108c7562..7c03120a91f0fc0a5cecbbff4cd7b2c0d0da2c94 100644 ---- a/testData/results/TestClassSimpleBytecodeMapping.dec -+++ b/testData/results/TestClassSimpleBytecodeMapping.dec -@@ -33,17 +33,17 @@ public class TestClassSimpleBytecodeMapping { - var1.run();// 49 - }// 50 - -- public class InnerClass2 { -- public void print() { -- System.out.println("Inner2");// 54 -- }// 55 -- } -- - public class InnerClass { - public void print() { - System.out.println("Inner");// 44 - }// 45 - } -+ -+ public class InnerClass2 { -+ public void print() { -+ System.out.println("Inner2");// 54 -+ }// 55 -+ } - } - - class 'pkg/TestClassSimpleBytecodeMapping$1' { -@@ -96,7 +96,7 @@ class 'pkg/TestClassSimpleBytecodeMapping' { - } - } - --class 'pkg/TestClassSimpleBytecodeMapping$InnerClass2' { -+class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' { - method 'print ()V' { - 0 37 - 3 37 -@@ -105,7 +105,7 @@ class 'pkg/TestClassSimpleBytecodeMapping$InnerClass2' { - } - } - --class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' { -+class 'pkg/TestClassSimpleBytecodeMapping$InnerClass2' { - method 'print ()V' { - 0 43 - 3 43 -@@ -130,11 +130,11 @@ Lines mapping: - 36 <-> 25 - 38 <-> 27 - 40 <-> 30 --44 <-> 44 --45 <-> 45 -+44 <-> 38 -+45 <-> 39 - 49 <-> 33 - 50 <-> 34 --54 <-> 38 --55 <-> 39 -+54 <-> 44 -+55 <-> 45 - Not mapped: - 39 -diff --git a/testData/results/TestExtendingSubclass.dec b/testData/results/TestExtendingSubclass.dec -index f7be1b46d3058aba92f7a21ffc9558068dd26226..6bab8435926e1c10171fc97b61075ec58dba2572 100644 ---- a/testData/results/TestExtendingSubclass.dec -+++ b/testData/results/TestExtendingSubclass.dec -@@ -1,35 +1,35 @@ - package pkg; - - public class TestExtendingSubclass { -+ class Subclass1 { -+ Subclass1(String name) { -+ }// 9 -+ } -+ - class Subclass2 extends Subclass1 { - Subclass2(String name) { - super(name);// 14 - }// 15 - } -- -- class Subclass1 { -- Subclass1(String name) { -- }// 9 -- } - } - --class 'pkg/TestExtendingSubclass$Subclass2' { -+class 'pkg/TestExtendingSubclass$Subclass1' { - method ' (Lpkg/TestExtendingSubclass;Ljava/lang/String;)V' { -- 8 5 -- b 6 -+ 9 5 - } - } - --class 'pkg/TestExtendingSubclass$Subclass1' { -+class 'pkg/TestExtendingSubclass$Subclass2' { - method ' (Lpkg/TestExtendingSubclass;Ljava/lang/String;)V' { -- 9 11 -+ 8 10 -+ b 11 - } - } - - Lines mapping: --9 <-> 12 --14 <-> 6 --15 <-> 7 -+9 <-> 6 -+14 <-> 11 -+15 <-> 12 - Not mapped: - 8 - 13 -diff --git a/testData/results/TestInnerLocal.dec b/testData/results/TestInnerLocal.dec -index b270e4eea9caf36d5c66b64d18e33ca8d8fcae10..9009b85453ba2aae2ac4e32f94fb082dcd6d3c81 100644 ---- a/testData/results/TestInnerLocal.dec -+++ b/testData/results/TestInnerLocal.dec -@@ -30,6 +30,14 @@ public class TestInnerLocal { - new Inner1Static.Inner2Static("test");// 26 - }// 27 - -+ class Inner1 { -+ final String x; -+ -+ public Inner1(String var2) { -+ this.x = var2;// 46 -+ }// 47 -+ } -+ - static class Inner1Static { - final String x; - -@@ -45,14 +53,6 @@ public class TestInnerLocal { - }// 46 - } - } -- -- class Inner1 { -- final String x; -- -- public Inner1(@Deprecated String x) { -- this.x = x;// 32 -- }// 33 -- } - } - - class 'pkg/TestInnerLocal$1Inner' { -@@ -86,47 +86,47 @@ class 'pkg/TestInnerLocal$2Inner' { - } - } - --class 'pkg/TestInnerLocal$Inner1Static' { -- method ' (Ljava/lang/String;)V' { -- 6 36 -- 9 37 -+class 'TestInnerLocal$Inner1' { -+ method ' (LTestInnerLocal;Ljava/lang/String;)V' { -+ b 34 -+ e 35 - } - } - --class 'pkg/TestInnerLocal$Inner1Static$Inner2Static' { -+class 'TestInnerLocal$Inner1Static' { - method ' (Ljava/lang/String;)V' { -- 6 43 -- 9 44 -+ 6 42 -+ 9 43 - } - } - --class 'pkg/TestInnerLocal$Inner1' { -- method ' (Lpkg/TestInnerLocal;Ljava/lang/String;)V' { -- b 52 -- e 53 -+class 'pkg/TestInnerLocal$Inner1Static$Inner2Static' { -+ method ' (Ljava/lang/String;)V' { -+ 6 49 -+ 9 50 - } - } - - Lines mapping: --8 <-> 9 --9 <-> 10 --11 <-> 13 --12 <-> 14 --13 <-> 15 --14 <-> 16 --20 <-> 23 --21 <-> 24 --23 <-> 27 --24 <-> 28 --25 <-> 29 --26 <-> 30 --27 <-> 31 --32 <-> 53 --33 <-> 54 --39 <-> 37 --40 <-> 38 --45 <-> 44 --46 <-> 45 -+22 <-> 7 -+23 <-> 8 -+25 <-> 11 -+26 <-> 12 -+27 <-> 13 -+28 <-> 14 -+34 <-> 21 -+35 <-> 22 -+37 <-> 25 -+38 <-> 26 -+39 <-> 27 -+40 <-> 28 -+41 <-> 29 -+46 <-> 35 -+47 <-> 36 -+53 <-> 43 -+54 <-> 44 -+59 <-> 50 -+60 <-> 51 - Not mapped: - 7 - 19 -diff --git a/testData/results/TestInnerSignature.dec b/testData/results/TestInnerSignature.dec -index b2e4d0f757e55cd9ab6bd77aa9ed0afb33989e7d..8aab3c2b9f56368f1350f1ac98262c761bf6ed19 100644 ---- a/testData/results/TestInnerSignature.dec -+++ b/testData/results/TestInnerSignature.dec -@@ -11,18 +11,6 @@ public class TestInnerSignature { - this.c = c;// 11 - }// 12 - -- public static class InnerStatic { -- A a; -- B b; -- C c; -- -- public InnerStatic(A a, @Deprecated B b, C c) { -- this.a = a;// 32 -- this.b = b;// 33 -- this.c = c;// 34 -- }// 35 -- } -- - public class Inner { - A a; - B b; -@@ -34,6 +22,18 @@ public class TestInnerSignature { - this.c = c;// 22 - }// 23 - } -+ -+ public static class InnerStatic { -+ A a; -+ B b; -+ C c; -+ -+ public InnerStatic(A var1, B var2, C var3) { -+ this.a = var1;// 46 -+ this.b = var2;// 47 -+ this.c = var3;// 48 -+ }// 49 -+ } - } - - class 'pkg/TestInnerSignature' { -@@ -45,37 +45,37 @@ class 'pkg/TestInnerSignature' { - } - } - --class 'pkg/TestInnerSignature$InnerStatic' { -- method ' (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { -- 6 19 -- b 20 -- 10 21 -- 13 22 -+class 'TestInnerSignature$Inner' { -+ method ' (LTestInnerSignature;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { -+ b 17 -+ 10 18 -+ 16 19 -+ 19 20 - } - } - --class 'pkg/TestInnerSignature$Inner' { -- method ' (Lpkg/TestInnerSignature;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { -- b 31 -- 10 32 -- 16 33 -- 19 34 -+class 'TestInnerSignature$InnerStatic' { -+ method ' (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { -+ 6 29 -+ b 30 -+ 10 31 -+ 13 32 - } - } - - Lines mapping: --9 <-> 9 --10 <-> 10 --11 <-> 11 --12 <-> 12 --20 <-> 32 --21 <-> 33 --22 <-> 34 --23 <-> 35 --32 <-> 20 --33 <-> 21 --34 <-> 22 --35 <-> 23 -+23 <-> 7 -+24 <-> 8 -+25 <-> 9 -+26 <-> 10 -+34 <-> 18 -+35 <-> 19 -+36 <-> 20 -+37 <-> 21 -+46 <-> 30 -+47 <-> 31 -+48 <-> 32 -+49 <-> 33 - Not mapped: - 8 - 19 -diff --git a/testData/results/TestMethodParameters.dec b/testData/results/TestMethodParameters.dec -index 21f0f129d1bc260e2dbc7ce77f07ece57711bf75..af7ce865f5d946980010ee02c3e5be384a041064 100644 ---- a/testData/results/TestMethodParameters.dec -+++ b/testData/results/TestMethodParameters.dec -@@ -21,6 +21,14 @@ public class TestMethodParameters { - - }// 39 - -+ class C1 { -+ C1(@Deprecated int var2) { -+ }// 24 -+ -+ void m(@Deprecated int var1) { -+ }// 25 -+ } -+ - static class C2 { - C2(@Deprecated int var1) { - }// 29 -@@ -31,14 +39,6 @@ public class TestMethodParameters { - static void m2(@Deprecated int var0) { - }// 31 - } -- -- class C1 { -- C1(@Deprecated int var2) { -- }// 24 -- -- void m(@Deprecated int var1) { -- }// 25 -- } - } - - class 'pkg/TestMethodParameters' { -@@ -69,26 +69,26 @@ class 'pkg/TestMethodParameters$1Local' { - } - } - --class 'pkg/TestMethodParameters$C2' { -- method ' (I)V' { -- 4 25 -+class 'pkg/TestMethodParameters$C1' { -+ method ' (Lpkg/TestMethodParameters;I)V' { -+ 9 25 - } - -- method 'm1 (I)V' { -+ method 'm (I)V' { - 0 28 - } -+} - -- method 'm2 (I)V' { -- 0 31 -+class 'pkg/TestMethodParameters$C2' { -+ method ' (I)V' { -+ 4 33 - } --} - --class 'pkg/TestMethodParameters$C1' { -- method ' (Lpkg/TestMethodParameters;I)V' { -- 9 36 -+ method 'm1 (I)V' { -+ 0 36 - } - -- method 'm (I)V' { -+ method 'm2 (I)V' { - 0 39 - } - } -@@ -97,11 +97,11 @@ Lines mapping: - 19 <-> 5 - 20 <-> 8 - 21 <-> 11 --24 <-> 37 --25 <-> 40 --29 <-> 26 --30 <-> 29 --31 <-> 32 -+24 <-> 26 -+25 <-> 29 -+29 <-> 34 -+30 <-> 37 -+31 <-> 40 - 36 <-> 16 - 37 <-> 19 - 39 <-> 22 -diff --git a/testData/results/TestSwitchOnEnum.dec b/testData/results/TestSwitchOnEnum.dec -index e63cfe50c3d0c9fddd4f3051d7bda5df33523cbb..6e1f77fa247005cb8bb012a91aff96ed78103204 100644 ---- a/testData/results/TestSwitchOnEnum.dec -+++ b/testData/results/TestSwitchOnEnum.dec -@@ -36,15 +36,15 @@ public class TestSwitchOnEnum { - - }// 46 - -- static enum B { -- B1, -- B2; -- } -- - static enum A { - A1, - A2; - } -+ -+ static enum B { -+ B1, -+ B2; -+ } - } - } - diff --git a/FernFlower-Patches/0004-Fixed-this-calls-not-having-arguments.patch b/FernFlower-Patches/0004-Fixed-this-calls-not-having-arguments.patch new file mode 100644 index 0000000..53bbdb6 --- /dev/null +++ b/FernFlower-Patches/0004-Fixed-this-calls-not-having-arguments.patch @@ -0,0 +1,57 @@ +From 723017cb1251c8f0ff9b09e97a8800109bc5375f Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sat, 1 Aug 2015 15:52:57 -0700 +Subject: [PATCH 004/122] Fixed this calls not having arguments. + +--- + .../modules/decompiler/exps/InvocationExprent.java | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +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 294a115..4e73f06 100644 +--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java ++++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +@@ -321,7 +321,7 @@ public class InvocationExprent extends Exprent { + boolean firstParameter = true; + int start = isEnum ? 2 : 0; + for (int i = start; i < lstParameters.size(); i++) { +- if (sigFields == null) { ++ if (sigFields == null || sigFields.get(i) == null) { + if (!firstParameter) { + buf.append(", "); + } +@@ -495,16 +495,16 @@ public class InvocationExprent extends Exprent { + // ***************************************************************************** + // IMatchable implementation + // ***************************************************************************** +- ++ + public boolean match(MatchNode matchNode, MatchEngine engine) { + + if(!super.match(matchNode, engine)) { + return false; + } +- ++ + for(Entry rule : matchNode.getRules().entrySet()) { + RuleValue value = rule.getValue(); +- ++ + switch(rule.getKey()) { + case EXPRENT_INVOCATION_PARAMETER: + if(value.isVariable()) { +@@ -528,9 +528,9 @@ public class InvocationExprent extends Exprent { + } + break; + } +- ++ + } +- ++ + return true; + } + +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0005-Convert-Exprent.bytecode-to-a-BitMap.patch b/FernFlower-Patches/0005-Convert-Exprent.bytecode-to-a-BitMap.patch deleted file mode 100644 index 2b12c8a..0000000 --- a/FernFlower-Patches/0005-Convert-Exprent.bytecode-to-a-BitMap.patch +++ /dev/null @@ -1,4516 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Wed, 12 Apr 2017 15:18:38 -0700 -Subject: [PATCH] Convert Exprent.bytecode to a BitMap. - -It gives better speed and functionality. Added method to gather bytecode markers for every expression. Allows us to get the bytecode offsets for an entire block of code. Also more aggressively capture bytecode ranges to better understand how much of the code we are processing/outputting - -diff --git a/src/org/jetbrains/java/decompiler/code/Instruction.java b/src/org/jetbrains/java/decompiler/code/Instruction.java -index 1a260f2bbd2c593351eb45f345b334045c93ad4c..91e64861d2b61ad952a713b308614c6c4e35ea14 100644 ---- a/src/org/jetbrains/java/decompiler/code/Instruction.java -+++ b/src/org/jetbrains/java/decompiler/code/Instruction.java -@@ -4,18 +4,18 @@ package org.jetbrains.java.decompiler.code; - import org.jetbrains.java.decompiler.util.TextUtil; - - public class Instruction implements CodeConstants { -- public static Instruction create(int opcode, boolean wide, int group, int bytecodeVersion, int[] operands) { -+ public static Instruction create(int opcode, boolean wide, int group, int bytecodeVersion, int[] operands, int length) { - if (opcode >= opc_ifeq && opcode <= opc_if_acmpne || - opcode == opc_ifnull || opcode == opc_ifnonnull || - opcode == opc_jsr || opcode == opc_jsr_w || - opcode == opc_goto || opcode == opc_goto_w) { -- return new JumpInstruction(opcode, group, wide, bytecodeVersion, operands); -+ return new JumpInstruction(opcode, group, wide, bytecodeVersion, operands, length); - } - else if (opcode == opc_tableswitch || opcode == opc_lookupswitch) { -- return new SwitchInstruction(opcode, group, wide, bytecodeVersion, operands); -+ return new SwitchInstruction(opcode, group, wide, bytecodeVersion, operands, length); - } - else { -- return new Instruction(opcode, group, wide, bytecodeVersion, operands); -+ return new Instruction(opcode, group, wide, bytecodeVersion, operands, length); - } - } - -@@ -31,15 +31,17 @@ public class Instruction implements CodeConstants { - public final int group; - public final boolean wide; - public final int bytecodeVersion; -+ public final int length; - - protected final int[] operands; - -- public Instruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) { -+ public Instruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands, int length) { - this.opcode = opcode; - this.group = group; - this.wide = wide; - this.bytecodeVersion = bytecodeVersion; - this.operands = operands; -+ this.length = length; - } - - public void initInstruction(InstructionSequence seq) { } -@@ -82,6 +84,6 @@ public class Instruction implements CodeConstants { - @Override - @SuppressWarnings("MethodDoesntCallSuperMethod") - public Instruction clone() { -- return create(opcode, wide, group, bytecodeVersion, operands == null ? null : operands.clone()); -+ return create(opcode, wide, group, bytecodeVersion, operands == null ? null : operands.clone(), length); - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/code/JumpInstruction.java b/src/org/jetbrains/java/decompiler/code/JumpInstruction.java -index 129df62e7295cbd4145880d2c215d5c1e717ffe6..1597df01326479fd8992af4b6e754dd6223a50e6 100644 ---- a/src/org/jetbrains/java/decompiler/code/JumpInstruction.java -+++ b/src/org/jetbrains/java/decompiler/code/JumpInstruction.java -@@ -4,8 +4,8 @@ package org.jetbrains.java.decompiler.code; - public class JumpInstruction extends Instruction { - public int destination; - -- public JumpInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) { -- super(opcode, group, wide, bytecodeVersion, operands); -+ public JumpInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands, int length) { -+ super(opcode, group, wide, bytecodeVersion, operands, length); - } - - @Override -diff --git a/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java b/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java -index 61810d96bea8e35006df80630e9caf029b33b41c..6379ccadaf4d0b7bf2a4001481b408dd33b3f7bd 100644 ---- a/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java -+++ b/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java -@@ -6,8 +6,8 @@ public class SwitchInstruction extends Instruction { - private int[] values; - private int defaultDestination; - -- public SwitchInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) { -- super(opcode, group, wide, bytecodeVersion, operands); -+ public SwitchInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands, int length) { -+ super(opcode, group, wide, bytecodeVersion, operands, length); - } - - @Override -@@ -58,4 +58,4 @@ public class SwitchInstruction extends Instruction { - copy.values = values.clone(); - return copy; - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java b/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java -index 28c4f50ec90546100a5f16e9c6d60aa931a00e0d..9eb4fbab0ede1b19bfaa9a433c182e00b4f07a0b 100644 ---- a/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java -+++ b/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java -@@ -149,4 +149,19 @@ public class BasicBlock implements IGraphNode { - public String toString() { - return id + ":" + DecompilerContext.getNewLineSeparator() + seq.toString(0); - } -+ -+ public int getStartInstruction() { -+ if (seq.isEmpty()) { -+ return 0; -+ } -+ return originalOffsets.get(0); -+ } -+ -+ public int getEndInstruction() { -+ if (seq.isEmpty()) { -+ return 0; -+ } -+ int end = seq.getLastInstr().length; -+ return end + originalOffsets.get(size() -1); -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java b/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java -index c6a23b3277c3a93be621d6686b1554d51be01c9b..32ca965883f26cd8944bfb5e838d5cf584142f68 100644 ---- a/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java -+++ b/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java -@@ -31,10 +31,10 @@ public class BytecodeMappingTracer { - mapping.putIfAbsent(bytecode_offset, currentSourceLine); - } - -- public void addMapping(Set bytecode_offsets) { -+ public void addMapping(BitSet bytecode_offsets) { - if (bytecode_offsets != null) { -- for (Integer bytecode_offset : bytecode_offsets) { -- addMapping(bytecode_offset); -+ for (int i = bytecode_offsets.nextSetBit(0); i >= 0; i = bytecode_offsets.nextSetBit(i+1)) { -+ addMapping(i); - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 6e5fe5474d6878d789758a5e7791b03e5da6685e..327a6e64f06d7ef60dc1bb3139aab490a2f7c2df 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -@@ -533,7 +533,7 @@ public class NestedClassProcessor { - if (mapParamsToNewVars.containsKey(varIndex)) { - VarVersionPair newVar = mapParamsToNewVars.get(varIndex); - method.varproc.getExternalVars().add(newVar); -- return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc); -+ return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode); - } - } - else if (exprent.type == Exprent.EXPRENT_FIELD) { -@@ -544,7 +544,7 @@ public class NestedClassProcessor { - // mapFieldsToNewVars.containsKey(key)) { - VarVersionPair newVar = mapFieldsToNewVars.get(key); - method.varproc.getExternalVars().add(newVar); -- return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc); -+ return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode); - } - } - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java -index f4cb77bea6031ddfe1197fb9d684f95ef39cda5a..5d47c847133cf0413365eddd5f1a2104b2f6ac6b 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java -@@ -11,8 +11,8 @@ import org.jetbrains.java.decompiler.struct.gen.VarType; - - import java.util.ArrayList; - import java.util.Arrays; -+import java.util.BitSet; - import java.util.List; --import java.util.Set; - - public final class ConcatenationHelper { - -@@ -125,7 +125,7 @@ public final class ConcatenationHelper { - return createConcatExprent(lstOperands, expr.bytecode); - } - -- private static Exprent createConcatExprent(List lstOperands, Set bytecode) { -+ private static Exprent createConcatExprent(List lstOperands, BitSet bytecode) { - // build exprent to return - Exprent func = lstOperands.get(0); - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -index 6783382a1c199ba33df1af3477d3cf5e13230b09..3b10e5b29ff9e344815592e533b6b04891fe294c 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -@@ -266,7 +266,15 @@ public class ExprProcessor implements CodeConstants { - for (int i = 0; i < seq.length(); i++) { - Instruction instr = seq.getInstr(i); - Integer offset = block.getOriginalOffset(i); -- Set offsets = offset >= 0 ? Set.of(offset) : null; -+ BitSet offsets = null; -+ if (offset >= 0) { -+ offsets = new BitSet(); -+ offsets.set(offset); -+ int end_offset = block.getOriginalOffset(i+1); -+ if (end_offset > offset) { -+ offsets.set(offset, end_offset); -+ } -+ } - - switch (instr.opcode) { - case opc_aconst_null: -@@ -307,7 +315,7 @@ public class ExprProcessor implements CodeConstants { - case opc_fload: - case opc_dload: - case opc_aload: -- pushEx(stack, exprList, new VarExprent(instr.operand(0), varTypes[instr.opcode - opc_iload], varProcessor, offset)); -+ pushEx(stack, exprList, new VarExprent(instr.operand(0), varTypes[instr.opcode - opc_iload], varProcessor, offsets)); - break; - case opc_iaload: - case opc_laload: -@@ -330,7 +338,10 @@ public class ExprProcessor implements CodeConstants { - case opc_astore: { - Exprent value = stack.pop(); - int varIndex = instr.operand(0); -- VarExprent left = new VarExprent(varIndex, varTypes[instr.opcode - opc_istore], varProcessor, nextMeaningfulOffset(block, i)); -+ if (offsets != null) { //TODO: Figure out why this nulls in some cases -+ offsets.set(offset, offset + instr.length); -+ } -+ VarExprent left = new VarExprent(varIndex, varTypes[instr.opcode - opc_istore], varProcessor, offsets); - exprList.add(new AssignmentExprent(left, value, offsets)); - break; - } -@@ -392,7 +403,7 @@ public class ExprProcessor implements CodeConstants { - pushEx(stack, exprList, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack, offsets)); - break; - case opc_iinc: { -- VarExprent varExpr = new VarExprent(instr.operand(0), VarType.VARTYPE_INT, varProcessor); -+ VarExprent varExpr = new VarExprent(instr.operand(0), VarType.VARTYPE_INT, varProcessor, offsets); - int type = instr.operand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD; - List operands = Arrays.asList(varExpr.copy(), new ConstExprent(VarType.VARTYPE_INT, Math.abs(instr.operand(1)), null)); - exprList.add(new AssignmentExprent(varExpr, new FunctionExprent(type, operands, offsets), offsets)); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java -index 878c12b061975d4060b8a44abffa3d60d35d17a3..b240e83853cff82f917a7fc9f80dab661dd7ceb9 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java -@@ -304,6 +304,7 @@ public class FinallyProcessor { - } - } - -+ final int storeLength = var <= 3 ? 1 : var <= 128 ? 2 : 4; - // disable semaphore at statement exit points - for (BasicBlock block : setTry) { - for (BasicBlock dest : block.getSuccessors()) { -@@ -311,8 +312,8 @@ public class FinallyProcessor { - if (dest != graph.getLast() && !setCopy.contains(dest)) { - // disable semaphore - SimpleInstructionSequence seq = new SimpleInstructionSequence(); -- seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{0}), -1); -- seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{var}), -1); -+ seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{0}, 1), -1); -+ seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{var}, storeLength), -1); - - // build a separate block - BasicBlock newBlock = new BasicBlock(++graph.last_id, seq); -@@ -331,11 +332,11 @@ public class FinallyProcessor { - } - - // enable semaphore at the statement entrance -- BasicBlock newHead = createHeadBlock(graph, 1, var, bytecodeVersion); -+ BasicBlock newHead = createHeadBlock(graph, 1, var, bytecodeVersion, storeLength); - insertBlockBefore(graph, head, newHead); - - // initialize semaphore with false -- BasicBlock newHeadInit = createHeadBlock(graph, 0, var, bytecodeVersion); -+ BasicBlock newHeadInit = createHeadBlock(graph, 0, var, bytecodeVersion, storeLength); - insertBlockBefore(graph, newHead, newHeadInit); - - setCopy.add(newHead); -@@ -352,10 +353,10 @@ public class FinallyProcessor { - } - - @NotNull -- private static BasicBlock createHeadBlock(ControlFlowGraph graph, int value, int var, int bytecodeVersion) { -+ private static BasicBlock createHeadBlock(ControlFlowGraph graph, int value, int var, int bytecodeVersion, int storeLength) { - SimpleInstructionSequence seq = new SimpleInstructionSequence(); -- seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{value}), -1); -- seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{var}), -1); -+ seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{value}, 1), -1); -+ seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{var}, storeLength), -1); - return new BasicBlock(++graph.last_id, seq); - } - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java -index a5e7ccf98c61f2fb585054c48fd967eeb4e70a49..bbd7bd0cb42057638e765c5bb675b8d30b9b6796 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java -@@ -92,6 +92,12 @@ public final class MergeHelper { - if (ifedge.getType() == EdgeType.BREAK) { - ifexpr.negateIf(); - } -+ -+ if (stat.getConditionExprent() != null) { -+ ifexpr.getCondition().addBytecodeOffsets(stat.getConditionExprent().bytecode); -+ } -+ ifexpr.getCondition().addBytecodeOffsets(lastif.getHeadexprent().bytecode); -+ - stat.setConditionExprent(ifexpr.getCondition()); - lastif.getFirst().removeSuccessor(ifedge); - lastif.removeSuccessor(elseedge); -@@ -146,6 +152,12 @@ public final class MergeHelper { - // negate condition (while header) - IfExprent ifexpr = (IfExprent)firstif.getHeadexprent().copy(); - ifexpr.negateIf(); -+ -+ if (stat.getConditionExprent() != null) { -+ ifexpr.getCondition().addBytecodeOffsets(stat.getConditionExprent().bytecode); -+ } -+ ifexpr.getCondition().addBytecodeOffsets(firstif.getHeadexprent().bytecode); -+ - stat.setConditionExprent(ifexpr.getCondition()); - - // remove edges -@@ -184,7 +196,12 @@ public final class MergeHelper { - stat.setLoopType(LoopType.WHILE); - - // no need to negate the while condition -- stat.setConditionExprent(((IfExprent)firstif.getHeadexprent().copy()).getCondition()); -+ IfExprent ifexpr = (IfExprent)firstif.getHeadexprent().copy(); -+ if (stat.getConditionExprent() != null) { -+ ifexpr.getCondition().addBytecodeOffsets(stat.getConditionExprent().bytecode); -+ } -+ ifexpr.getCondition().addBytecodeOffsets(firstif.getHeadexprent().bytecode); -+ stat.setConditionExprent(ifexpr.getCondition()); - - // remove edges - StatEdge ifedge = firstif.getIfEdge(); -@@ -336,9 +353,17 @@ public final class MergeHelper { - - stat.setLoopType(LoopType.FOR); - if (hasinit) { -- stat.setInitExprent(preData.getExprents().remove(preData.getExprents().size() - 1)); -+ Exprent exp = preData.getExprents().remove(preData.getExprents().size() - 1); -+ if (stat.getInitExprent() != null) { -+ exp.addBytecodeOffsets(stat.getInitExprent().bytecode); -+ } -+ stat.setInitExprent(exp); -+ } -+ Exprent exp = lastData.getExprents().remove(lastData.getExprents().size() - 1); -+ if (stat.getIncExprent() != null) { -+ exp.addBytecodeOffsets(stat.getIncExprent().bytecode); - } -- stat.setIncExprent(lastData.getExprents().remove(lastData.getExprents().size() - 1)); -+ stat.setIncExprent(exp); - } - - if (lastData.getExprents().isEmpty()) { -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java -index 7a2376d0c0a2d4c18ca3ce8a4f35c0ae75bed962..eb96762fa2174047a3f9dcecfb8c57bf4721c11f 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java -@@ -641,7 +641,7 @@ public class SimplifyExprentsHelper { - if (stat.type == StatementType.IF && stat.getExprents() == null) { - IfStatement statement = (IfStatement)stat; - Exprent ifHeadExpr = statement.getHeadexprent(); -- Set ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode); -+ BitSet ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode); - - if (statement.iftype == IfStatement.IFTYPE_IFELSE) { - Statement ifStatement = statement.getIfstat(); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java b/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java -index ae166cc9ea414d5a0b698d8d06c7a24836c21316..478a3aef4cbc9d555abd82e38200a62ba7aa9a23 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java -@@ -404,8 +404,8 @@ public final class ExceptionDeobfuscator { - for (ExceptionRangeCFG range : ranges) { - // add some dummy instructions to prevent optimizing away the empty block - SimpleInstructionSequence seq = new SimpleInstructionSequence(); -- seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}), -1); -- seq.addInstruction(Instruction.create(CodeConstants.opc_pop, false, CodeConstants.GROUP_GENERAL, bytecode_version, null), -1); -+ seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}, 1), -1); -+ seq.addInstruction(Instruction.create(CodeConstants.opc_pop, false, CodeConstants.GROUP_GENERAL, bytecode_version, null, 1), -1); - - BasicBlock dummyBlock = new BasicBlock(++graph.last_id, seq); - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java -index 05849823262a46b66561164a0f0257123ce5307a..4beaf1ee874de373d956177ece541f0ecce64dc4 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java -@@ -6,6 +6,7 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.util.TextBuffer; - -+import java.util.BitSet; - import java.util.List; - import java.util.Objects; - -@@ -97,4 +98,10 @@ public class AnnotationExprent extends Exprent { - parNames.equals(ann.parNames) && - parValues.equals(ann.parValues); - } -+ -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, parValues); -+ measureBytecode(values); -+ } - } -\ No newline at end of file -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java -index e2b79d56e9f7c2ca22713e83dbd2aeddce5f9885..406848324e427a2b18d3666e321172f0f130ec4c 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java -@@ -14,7 +14,7 @@ public class ArrayExprent extends Exprent { - private Exprent index; - private final VarType hardType; - -- public ArrayExprent(Exprent array, Exprent index, VarType hardType, Set bytecodeOffsets) { -+ public ArrayExprent(Exprent array, Exprent index, VarType hardType, BitSet bytecodeOffsets) { - super(EXPRENT_ARRAY); - this.array = array; - this.index = index; -@@ -105,4 +105,11 @@ public class ArrayExprent extends Exprent { - public Exprent getIndex() { - return index; - } -+ -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, array); -+ measureBytecode(values, index); -+ measureBytecode(values); -+ } - } -\ No newline at end of file -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java -index 0dcb63d34c036a9cd21e21d77c2ea01f6f5b9266..097c10a32ed819368c48efa51866420c01584395 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java -@@ -6,6 +6,7 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; - import org.jetbrains.java.decompiler.util.TextBuffer; - import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - -+import java.util.BitSet; - import java.util.List; - - public class AssertExprent extends Exprent { -@@ -39,4 +40,10 @@ public class AssertExprent extends Exprent { - - return buffer; - } -+ -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, parameters); -+ measureBytecode(values); -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -index b8678cdc0f0e778c3d1c8834ae764bbaa2e77ae1..06567749310f70d0f3263a9b2bad4588237bdda9 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -@@ -36,7 +36,7 @@ public class AssignmentExprent extends Exprent { - private Exprent right; - private int condType = CONDITION_NONE; - -- public AssignmentExprent(Exprent left, Exprent right, Set bytecodeOffsets) { -+ public AssignmentExprent(Exprent left, Exprent right, BitSet bytecodeOffsets) { - super(EXPRENT_ASSIGNMENT); - this.left = left; - this.right = right; -@@ -165,6 +165,13 @@ public class AssignmentExprent extends Exprent { - condType == as.getCondType(); - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, left); -+ measureBytecode(values, right); -+ measureBytecode(values); -+ } -+ - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index 623d59228cc526cca3bbd52e95e4d493c689f133..b0bda600031b4cc52b6b083d5afd07a92ccef1af 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -@@ -52,20 +52,20 @@ public class ConstExprent extends Exprent { - private final Object value; - private final boolean boolPermitted; - -- public ConstExprent(int val, boolean boolPermitted, Set bytecodeOffsets) { -+ public ConstExprent(int val, boolean boolPermitted, BitSet bytecodeOffsets) { - this(guessType(val, boolPermitted), val, boolPermitted, bytecodeOffsets); - } - -- public ConstExprent(VarType constType, Object value, Set bytecodeOffsets) { -+ public ConstExprent(VarType constType, Object value, BitSet bytecodeOffsets) { - this(constType, value, false, bytecodeOffsets); - } - -- public ConstExprent(VarType constType, Object value, Set bytecodeOffsets, StructMember parent) { -+ public ConstExprent(VarType constType, Object value, BitSet bytecodeOffsets, StructMember parent) { - this(constType, value, bytecodeOffsets); - this.parent = parent; - } - -- private ConstExprent(VarType constType, Object value, boolean boolPermitted, Set bytecodeOffsets) { -+ private ConstExprent(VarType constType, Object value, boolean boolPermitted, BitSet bytecodeOffsets) { - super(EXPRENT_CONST); - this.constType = constType; - this.value = value; -@@ -496,6 +496,11 @@ public class ConstExprent extends Exprent { - return boolPermitted; - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values); -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -index 655e56241cf1d4eaa8bad524851f682c7af2bfb9..54f6a306cd28f68879d25a536a1dea7a496a4aa3 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -@@ -16,9 +16,9 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.util.TextBuffer; - - import java.util.ArrayList; -+import java.util.BitSet; - import java.util.List; - import java.util.Objects; --import java.util.Set; - - public class ExitExprent extends Exprent { - -@@ -29,7 +29,7 @@ public class ExitExprent extends Exprent { - private Exprent value; - private final VarType retType; - -- public ExitExprent(int exitType, Exprent value, VarType retType, Set bytecodeOffsets) { -+ public ExitExprent(int exitType, Exprent value, VarType retType, BitSet bytecodeOffsets) { - super(EXPRENT_EXIT); - this.exitType = exitType; - this.value = value; -@@ -140,6 +140,13 @@ public class ExitExprent extends Exprent { - return retType; - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, value); -+ measureBytecode(values); -+ } -+ -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -index 9b1b3de632a63bbba1f5f7a99d5f75bf537bd171..67fc1f2beab815f0ca07ecf8a34b98fa23344749 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -@@ -16,7 +16,7 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue; - - import java.util.ArrayList; --import java.util.Collection; -+import java.util.BitSet; - import java.util.Collections; - import java.util.Comparator; - import java.util.HashSet; -@@ -24,7 +24,7 @@ import java.util.List; - import java.util.Map.Entry; - import java.util.Set; - --public class Exprent implements IMatchable { -+public abstract class Exprent implements IMatchable { - public static final int MULTIPLE_USES = 1; - public static final int SIDE_EFFECTS_FREE = 2; - public static final int BOTH_FLAGS = 3; -@@ -46,7 +46,7 @@ public class Exprent implements IMatchable { - - public final int type; - public final int id; -- public Set bytecode = null; // offsets of bytecode instructions decompiled to this exprent -+ public BitSet bytecode = null; // offsets of bytecode instructions decompiled to this exprent - - public Exprent(int type) { - this.type = type; -@@ -123,14 +123,31 @@ public class Exprent implements IMatchable { - - public void replaceExprent(Exprent oldExpr, Exprent newExpr) { } - -- public void addBytecodeOffsets(Collection bytecodeOffsets) { -- if (bytecodeOffsets != null && !bytecodeOffsets.isEmpty()) { -+ public void addBytecodeOffsets(BitSet bytecodeOffsets) { -+ if (bytecodeOffsets != null) { - if (bytecode == null) { -- bytecode = new HashSet<>(bytecodeOffsets); -- } -- else { -- bytecode.addAll(bytecodeOffsets); -+ bytecode = new BitSet(); - } -+ bytecode.or(bytecodeOffsets); -+ } -+ } -+ -+ public abstract void getBytecodeRange(BitSet values); -+ -+ protected void measureBytecode(BitSet values) { -+ if (bytecode != null) -+ values.or(bytecode); -+ } -+ -+ protected static void measureBytecode(BitSet values, Exprent exprent) { -+ if (exprent != null) -+ exprent.getBytecodeRange(values); -+ } -+ -+ protected static void measureBytecode(BitSet values, List list) { -+ if (list != null && !list.isEmpty()) { -+ for (Exprent e : list) -+ e.getBytecodeRange(values); - } - } - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -index 4cd97c42682b27f96414ddf5302fc81db2561e56..379242393a83c6b3502a88c8d745a5b0bc1b5476 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -@@ -19,9 +19,9 @@ import org.jetbrains.java.decompiler.util.TextBuffer; - import org.jetbrains.java.decompiler.util.TextUtil; - - import java.util.ArrayList; -+import java.util.BitSet; - import java.util.List; - import java.util.Objects; --import java.util.Set; - - public class FieldExprent extends Exprent { - private final String name; -@@ -30,11 +30,11 @@ public class FieldExprent extends Exprent { - private Exprent instance; - private final FieldDescriptor descriptor; - -- public FieldExprent(LinkConstant cn, Exprent instance, Set bytecodeOffsets) { -+ public FieldExprent(LinkConstant cn, Exprent instance, BitSet bytecodeOffsets) { - this(cn.elementname, cn.classname, instance == null, instance, FieldDescriptor.parseDescriptor(cn.descriptor), bytecodeOffsets); - } - -- public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor, Set bytecodeOffsets) { -+ public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor, BitSet bytecodeOffsets) { - super(EXPRENT_FIELD); - this.name = name; - this.classname = classname; -@@ -182,6 +182,12 @@ public class FieldExprent extends Exprent { - return name; - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, instance); -+ measureBytecode(values); -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index 4290039f07249ef112eb357ba0c9914ef5c08b40..b2b26fb3f8b075182caee14d57b4cc351ffb120a 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -@@ -183,7 +183,7 @@ public class FunctionExprent extends Exprent { - private VarType implicitType; - private final List lstOperands; - -- public FunctionExprent(int funcType, ListStack stack, Set bytecodeOffsets) { -+ public FunctionExprent(int funcType, ListStack stack, BitSet bytecodeOffsets) { - this(funcType, new ArrayList<>(), bytecodeOffsets); - - if (funcType >= FUNCTION_BIT_NOT && funcType <= FUNCTION_PPI && funcType != FUNCTION_CAST && funcType != FUNCTION_INSTANCEOF) { -@@ -199,7 +199,7 @@ public class FunctionExprent extends Exprent { - } - } - -- public FunctionExprent(int funcType, List operands, Set bytecodeOffsets) { -+ public FunctionExprent(int funcType, List operands, BitSet bytecodeOffsets) { - super(EXPRENT_FUNCTION); - this.funcType = funcType; - this.lstOperands = operands; -@@ -207,7 +207,7 @@ public class FunctionExprent extends Exprent { - addBytecodeOffsets(bytecodeOffsets); - } - -- public FunctionExprent(int funcType, Exprent operand, Set bytecodeOffsets) { -+ public FunctionExprent(int funcType, Exprent operand, BitSet bytecodeOffsets) { - this(funcType, new ArrayList<>(1), bytecodeOffsets); - lstOperands.add(operand); - } -@@ -565,6 +565,12 @@ public class FunctionExprent extends Exprent { - this.implicitType = implicitType; - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, lstOperands); -+ measureBytecode(values); -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java -index fda309fdc9d9fcaba4d089778122a56d1524e083..7c9ee0a57cd291ae20b466d70f57a8f11bf4abaa 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java -@@ -9,9 +9,9 @@ import org.jetbrains.java.decompiler.util.ListStack; - import org.jetbrains.java.decompiler.util.TextBuffer; - - import java.util.ArrayList; -+import java.util.BitSet; - import java.util.List; - import java.util.Objects; --import java.util.Set; - - public class IfExprent extends Exprent { - -@@ -64,7 +64,7 @@ public class IfExprent extends Exprent { - - private Exprent condition; - -- public IfExprent(int ifType, ListStack stack, Set bytecodeOffsets) { -+ public IfExprent(int ifType, ListStack stack, BitSet bytecodeOffsets) { - this(null, bytecodeOffsets); - - if (ifType <= IF_LE) { -@@ -82,7 +82,7 @@ public class IfExprent extends Exprent { - } - } - -- private IfExprent(Exprent condition, Set bytecodeOffsets) { -+ private IfExprent(Exprent condition, BitSet bytecodeOffsets) { - super(EXPRENT_IF); - this.condition = condition; - -@@ -134,4 +134,10 @@ public class IfExprent extends Exprent { - public void setCondition(Exprent condition) { - this.condition = condition; - } --} -\ No newline at end of file -+ -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, condition); -+ measureBytecode(values); -+ } -+} -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 dc9c2a593185c2f5de7289b0c7676071bf50f5a4..3cedf46af2faa91029231205455a1df1db7be3de 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -@@ -65,7 +65,7 @@ public class InvocationExprent extends Exprent { - LinkConstant cn, - List bootstrapArguments, - ListStack stack, -- Set bytecodeOffsets) { -+ BitSet bytecodeOffsets) { - this(); - - name = cn.elementname; -@@ -602,6 +602,13 @@ public class InvocationExprent extends Exprent { - return bootstrapArguments; - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, parameters); -+ measureBytecode(values, instance); -+ measureBytecode(values); -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java -index 7259ce4ee91540cabf7a76105a5f18b2ab0390fa..cd465813bc3e9076d3bbafd1c7b10c9bed0a1407 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java -@@ -7,9 +7,9 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.util.TextBuffer; - - import java.util.ArrayList; -+import java.util.BitSet; - import java.util.List; - import java.util.Objects; --import java.util.Set; - - public class MonitorExprent extends Exprent { - -@@ -19,7 +19,7 @@ public class MonitorExprent extends Exprent { - private final int monType; - private Exprent value; - -- public MonitorExprent(int monType, Exprent value, Set bytecodeOffsets) { -+ public MonitorExprent(int monType, Exprent value, BitSet bytecodeOffsets) { - super(EXPRENT_MONITOR); - this.monType = monType; - this.value = value; -@@ -74,4 +74,10 @@ public class MonitorExprent extends Exprent { - public Exprent getValue() { - return value; - } -+ -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, value); -+ measureBytecode(values); -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -index 2f8da49a36ee84e09ff6192aea5d0904c4f06255..c47ae33d7d62a5049a89bb586032fc18bdc80173 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -@@ -31,11 +31,11 @@ public class NewExprent extends Exprent { - private boolean lambda; - private boolean enumConst; - -- public NewExprent(VarType newType, ListStack stack, int arrayDim, Set bytecodeOffsets) { -+ public NewExprent(VarType newType, ListStack stack, int arrayDim, BitSet bytecodeOffsets) { - this(newType, getDimensions(arrayDim, stack), bytecodeOffsets); - } - -- public NewExprent(VarType newType, List lstDims, Set bytecodeOffsets) { -+ public NewExprent(VarType newType, List lstDims, BitSet bytecodeOffsets) { - super(EXPRENT_NEW); - this.newType = newType; - this.lstDims = lstDims; -@@ -435,6 +435,14 @@ public class NewExprent extends Exprent { - Objects.equals(lstArrayElements, ne.lstArrayElements); - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values, lstArrayElements); -+ measureBytecode(values, lstDims); -+ measureBytecode(values, constructor); -+ measureBytecode(values); -+ } -+ - public InvocationExprent getConstructor() { - return constructor; - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java -index f475db7b7441d47661340b366116dbae7b1d9e5e..11000d30cbdc93e360cb1bc96b53987bc692e3bd 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java -@@ -9,16 +9,16 @@ import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.util.TextBuffer; - - import java.util.ArrayList; -+import java.util.BitSet; - import java.util.List; - import java.util.Objects; --import java.util.Set; - - public class SwitchExprent extends Exprent { - - private Exprent value; - private List> caseValues = new ArrayList<>(); - -- public SwitchExprent(Exprent value, Set bytecodeOffsets) { -+ public SwitchExprent(Exprent value, BitSet bytecodeOffsets) { - super(EXPRENT_SWITCH); - this.value = value; - -@@ -99,6 +99,22 @@ public class SwitchExprent extends Exprent { - return Objects.equals(value, sw.getValue()); - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ if (caseValues != null && !caseValues.isEmpty()) { -+ for (List l : caseValues) { -+ if (l != null && !l.isEmpty()) { -+ for (Exprent e : l) { -+ if (e != null) -+ e.getBytecodeRange(values); -+ } -+ } -+ } -+ } -+ measureBytecode(values, value); -+ measureBytecode(values); -+ } -+ - public Exprent getValue() { - return value; - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index e488a34ea11ab46cd1bd6383cd332f05d45df2af..2b508a172340285dff5afa73cd4d7fcbf0dfeaff 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -@@ -26,6 +26,7 @@ import org.jetbrains.java.decompiler.util.TextUtil; - - import java.util.ArrayList; - import java.util.Collections; -+import java.util.BitSet; - import java.util.List; - import java.util.Objects; - -@@ -37,21 +38,20 @@ public class VarExprent extends Exprent { - private VarType varType; - private boolean definition = false; - private final VarProcessor processor; -- private final int visibleOffset; - private int version = 0; - private boolean classDef = false; - private boolean stack = false; - - public VarExprent(int index, VarType varType, VarProcessor processor) { -- this(index, varType, processor, -1); -+ this(index, varType, processor, null); - } - -- public VarExprent(int index, VarType varType, VarProcessor processor, int visibleOffset) { -+ public VarExprent(int index, VarType varType, VarProcessor processor, BitSet bytecode) { - super(EXPRENT_VAR); - this.index = index; - this.varType = varType; - this.processor = processor; -- this.visibleOffset = visibleOffset; -+ this.addBytecodeOffsets(bytecode); - } - - @Override -@@ -71,7 +71,7 @@ public class VarExprent extends Exprent { - - @Override - public Exprent copy() { -- VarExprent var = new VarExprent(index, getVarType(), processor, visibleOffset); -+ VarExprent var = new VarExprent(index, getVarType(), processor, bytecode); - var.setDefinition(definition); - var.setVersion(version); - var.setClassDef(classDef); -@@ -120,7 +120,7 @@ public class VarExprent extends Exprent { - if (attr != null && processor != null) { - Integer origIndex = processor.getVarOriginalIndex(index); - if (origIndex != null) { -- String name = attr.getName(origIndex, visibleOffset); -+ String name = attr.getName(origIndex, bytecode == null ? -1 : bytecode.nextSetBit(0)); - if (name != null && TextUtil.isValidIdentifier(name, method.getBytecodeVersion())) { - return name; - } -@@ -137,6 +137,7 @@ public class VarExprent extends Exprent { - if (processor != null) { - originalIndex = processor.getVarOriginalIndex(index); - } -+ int visibleOffset = bytecode == null ? -1 : bytecode.length(); - if (originalIndex != null) { - // first try from signature - if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -@@ -180,6 +181,11 @@ public class VarExprent extends Exprent { - Objects.equals(getVarType(), ve.getVarType()); // FIXME: varType comparison redundant? - } - -+ @Override -+ public void getBytecodeRange(BitSet values) { -+ measureBytecode(values); -+ } -+ - public int getIndex() { - return index; - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java -index 6510e1dca6733eb28ceb0a774a658f893b3a8935..98e1c189d302ac71e01949511dc9f9c035b85e5a 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java -@@ -10,6 +10,7 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.main.collectors.CounterContainer; - import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.util.TextBuffer; -+import org.jetbrains.java.decompiler.util.StartEndPair; - - public class BasicBlockStatement extends Statement { - private final BasicBlock block; -@@ -58,4 +59,13 @@ public class BasicBlockStatement extends Statement { - public BasicBlock getBlock() { - return block; - } -+ -+ @Override -+ public StartEndPair getStartEndRange() { -+ if (block.size() > 0) { -+ return new StartEndPair(block.getStartInstruction(), block.getEndInstruction()); -+ } else { -+ return new StartEndPair(0, 0); -+ } -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DummyExitStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DummyExitStatement.java -index b0cca026cbe68b2741a6ca01a50c6a46be128bc8..b1c9165f9a4a2135128d22a3971303cc4d763a94 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DummyExitStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DummyExitStatement.java -@@ -1,25 +1,21 @@ - // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - package org.jetbrains.java.decompiler.modules.decompiler.stats; - --import java.util.Collection; --import java.util.HashSet; --import java.util.Set; -+import java.util.BitSet; - - public class DummyExitStatement extends Statement { -- public Set bytecode = null; // offsets of bytecode instructions mapped to dummy exit -+ public BitSet bytecode = null; // offsets of bytecode instructions mapped to dummy exit - - public DummyExitStatement() { - super(StatementType.DUMMY_EXIT); - } - -- public void addBytecodeOffsets(Collection bytecodeOffsets) { -+ public void addBytecodeOffsets(BitSet bytecodeOffsets) { - if (bytecodeOffsets != null && !bytecodeOffsets.isEmpty()) { - if (bytecode == null) { -- bytecode = new HashSet<>(bytecodeOffsets); -- } -- else { -- bytecode.addAll(bytecodeOffsets); -+ bytecode = new BitSet(); - } -+ bytecode.or(bytecodeOffsets); - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java -index 300314e0197e3914f8365c4acab064fec4e78445..611f501b4c94d15d557edf991eb84cd9eb7d4173 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java -@@ -12,6 +12,7 @@ import org.jetbrains.java.decompiler.struct.match.IMatchable; - import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.util.TextBuffer; -+import org.jetbrains.java.decompiler.util.StartEndPair; - import org.jetbrains.java.decompiler.util.TextUtil; - - import java.util.ArrayList; -@@ -409,6 +410,13 @@ public final class IfStatement extends Statement { - return elseedge; - } - -+ @Override -+ public StartEndPair getStartEndRange() { -+ return StartEndPair.join(super.getStartEndRange(), -+ ifstat != null ? ifstat.getStartEndRange() : null, -+ elsestat != null ? elsestat.getStartEndRange(): null); -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java -index 0946904c8610c2d21de597361e0adf377e88a675..163efe83fdfd94ccb945509fe4593f8495f467bb 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java -@@ -4,6 +4,7 @@ package org.jetbrains.java.decompiler.modules.decompiler.stats; - import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.util.TextBuffer; -+import org.jetbrains.java.decompiler.util.StartEndPair; - - public class RootStatement extends Statement { - private final DummyExitStatement dummyExit; -@@ -26,4 +27,9 @@ public class RootStatement extends Statement { - public DummyExitStatement getDummyExit() { - return dummyExit; - } --} -\ No newline at end of file -+ -+ @Override -+ public StartEndPair getStartEndRange() { -+ return StartEndPair.join(first.getStartEndRange(), dummyExit != null ? dummyExit.getStartEndRange() : null); -+ } -+} -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -index 224d3636f7c9d502cc65c122f542324c1ba7028a..9498f3c548d18ead3bcbc076222bd5ace82b8275 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -@@ -19,6 +19,7 @@ import org.jetbrains.java.decompiler.struct.match.IMatchable; - import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue; -+import org.jetbrains.java.decompiler.util.StartEndPair; - import org.jetbrains.java.decompiler.util.TextBuffer; - import org.jetbrains.java.decompiler.util.VBStyleCollection; - -@@ -796,6 +797,40 @@ public abstract class Statement implements IMatchable { - return Integer.toString(id); - } - -+ //TODO: Cleanup/cache? -+ public void getOffset(BitSet values) { -+ if (this instanceof DummyExitStatement && ((DummyExitStatement)this).bytecode != null) -+ values.or(((DummyExitStatement)this).bytecode); -+ if (this.getExprents() != null) { -+ for (Exprent e : this.getExprents()) { -+ e.getBytecodeRange(values); -+ } -+ } else { -+ for (Object obj : this.getSequentialObjects()) { -+ if (obj == null) { -+ //Humm? Skip it -+ } else if (obj instanceof Statement) { -+ ((Statement)obj).getOffset(values); -+ } else if (obj instanceof Exprent) { -+ ((Exprent)obj).getBytecodeRange(values); -+ } else { -+ System.out.println("WTF?" + obj.getClass()); -+ } -+ } -+ } -+ } -+ -+ private StartEndPair endpoints; -+ public StartEndPair getStartEndRange() { -+ if (endpoints == null) { -+ BitSet set = new BitSet(); -+ getOffset(set); -+ endpoints = new StartEndPair(set.nextSetBit(0), set.length() - 1); -+ } -+ return endpoints; -+ } -+ -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java -index 119949c8bd35082b95cbfde2b185aa2d23034224..18e40f99948e63d8e1d6136b4d1d5eadefd97330 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java -@@ -19,6 +19,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.SwitchExprent; - import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.util.StartEndPair; - import org.jetbrains.java.decompiler.util.TextBuffer; - - import java.util.*; -@@ -170,6 +171,17 @@ public final class SwitchStatement extends Statement { - sortEdgesAndNodes(); - } - -+ @Override -+ public StartEndPair getStartEndRange() { -+ StartEndPair[] sepairs = new StartEndPair[caseStatements.size() + 1]; -+ int i = 0; -+ sepairs[i++] = super.getStartEndRange(); -+ for (Statement st : caseStatements) { -+ sepairs[i++] = st.getStartEndRange(); -+ } -+ return StartEndPair.join(sepairs); -+ } -+ - public void sortEdgesAndNodes() { - Map edgeIndicesMapping = new HashMap<>(); - List firstSuccessors = first.getSuccessorEdges(EdgeType.DIRECT_ALL); -diff --git a/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/src/org/jetbrains/java/decompiler/struct/StructMethod.java -index b908ed26c27a60dd01f056b736490ebdf25dc125..470965603db2b5ffda4c2776549fcfbba5e7ee72 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructMethod.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructMethod.java -@@ -253,11 +253,11 @@ public class StructMethod extends StructMember { - } - } - -- Instruction instr = Instruction.create(opcode, wide, group, bytecodeVersion, ops); -+ i++; - -- instructions.addWithKey(instr, offset); -+ Instruction instr = Instruction.create(opcode, wide, group, bytecodeVersion, ops, i - offset); - -- i++; -+ instructions.addWithKey(instr, offset); - } - - // initialize exception table -diff --git a/src/org/jetbrains/java/decompiler/util/StartEndPair.java b/src/org/jetbrains/java/decompiler/util/StartEndPair.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ded36aadd72242ba74e3392e0891c6c82ac6b920 ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/util/StartEndPair.java -@@ -0,0 +1,51 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler.util; -+ -+public class StartEndPair { -+ public final int start; -+ public final int end; -+ public StartEndPair(int start, int end) { -+ this.start = start; -+ this.end = end; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ return ((StartEndPair)obj).start == start && ((StartEndPair)obj).end == end; -+ } -+ -+ @Override -+ public int hashCode() { -+ return start * 31 + end; -+ } -+ -+ @Override -+ public String toString() { -+ return String.format("%d->%d",start,end); -+ } -+ -+ public static StartEndPair join(StartEndPair... pairs) { -+ int start = Integer.MAX_VALUE; -+ int end = Integer.MIN_VALUE; -+ for (StartEndPair pair : pairs) { -+ if (pair == null) continue; -+ start = Math.min(start, pair.start); -+ end = Math.max(end, pair.end); -+ } -+ return new StartEndPair(start, end); -+ } -+} -diff --git a/testData/results/InvalidMethodSignature.dec b/testData/results/InvalidMethodSignature.dec -index e4b567c433b4a80e0c01119a8f115611dffe93be..ce8afaba80cd2197e1831af1af6be13da86962cb 100644 ---- a/testData/results/InvalidMethodSignature.dec -+++ b/testData/results/InvalidMethodSignature.dec -@@ -26,19 +26,51 @@ class i implements bg { - - class 'a/a/a/a/e/f/i' { - method ' (La/a/a/a/e/f/b;La/a/a/a/c/j;)V' { -+ 0 13 -+ 1 13 - 2 13 -+ 3 13 -+ 4 13 -+ 5 14 -+ 6 14 - 7 14 -+ 8 14 -+ 9 14 - e 15 - } - - method 'a (La/a/a/a/c/c;La/a/a/a/a/k;Z)V' { -+ 0 18 - 1 18 -+ 2 18 -+ 3 18 - 4 18 -+ 5 18 -+ 6 18 -+ 7 18 -+ 8 18 -+ 9 18 - a 18 -+ b 18 -+ c 18 -+ d 18 -+ e 18 - f 18 -+ 10 18 -+ 11 19 - 12 19 -+ 13 19 -+ 14 19 - 15 19 -+ 16 19 -+ 17 19 -+ 18 19 -+ 19 19 - 1a 19 -+ 1b 19 -+ 1c 19 -+ 1d 19 -+ 1e 19 - 20 20 - } - -diff --git a/testData/results/TestAbstractMethods.dec b/testData/results/TestAbstractMethods.dec -index 781cbfcf0bf85491e31f60dc3087d3106436ed1b..c0e60eb5262ee228d5eb57719bd4caddc8c90651 100644 ---- a/testData/results/TestAbstractMethods.dec -+++ b/testData/results/TestAbstractMethods.dec -@@ -16,12 +16,18 @@ public abstract class TestAbstractMethods { - - class 'pkg/TestAbstractMethods' { - method 'test (I)I' { -+ 0 6 - 1 6 - } - - method 'test2 (Ljava/lang/String;)V' { - 0 12 -+ 1 12 -+ 2 12 -+ 3 12 - 4 12 -+ 5 12 -+ 6 12 - 7 13 - } - } -diff --git a/testData/results/TestAccessReplace.dec b/testData/results/TestAccessReplace.dec -index f365126e79b21d9cc1d59591a00f219bf0755424..83d1eb2fac3378e5d556aeeebc70bb83a4e5cba8 100644 ---- a/testData/results/TestAccessReplace.dec -+++ b/testData/results/TestAccessReplace.dec -@@ -15,7 +15,7 @@ public class TestAccessReplace { - - public class Inner { - public Inner(String b) { -- TestAccessReplace.fooS();// 26 -+ TestAccessReplace.fooS();// 25 - TestAccessReplace.this.foo();// 27 - TestAccessReplace.fooSParams(1L, 2L);// 28 - TestAccessReplace.this.fooParams(1L, 2L);// 29 -@@ -43,14 +43,22 @@ class 'pkg/TestAccessReplace' { - - class 'pkg/TestAccessReplace$Inner' { - method ' (Lpkg/TestAccessReplace;Ljava/lang/String;)V' { -- 9 17 -- d 18 -+ 0 17 -+ 1 17 -+ 2 17 -+ 3 18 -+ 4 19 -+ 5 20 -+ c 18 - 10 19 - 11 19 -- 14 19 -+ 12 19 -+ 13 19 -+ 17 20 - 18 20 - 19 20 -- 1c 20 -+ 1a 20 -+ 1b 20 - 1f 21 - } - } -@@ -60,10 +68,10 @@ Lines mapping: - 20 <-> 8 - 21 <-> 11 - 22 <-> 14 --26 <-> 18 -+25 <-> 18 - 27 <-> 19 - 28 <-> 20 - 29 <-> 21 - 30 <-> 22 - Not mapped: --25 -+26 -diff --git a/testData/results/TestAmbiguousCall.dec b/testData/results/TestAmbiguousCall.dec -index a48730dcfb207c76a0959c5c34d59c5d3d503897..dec7ba0f20eecdc5a3c7d0774a0fdd4f3b68e6f6 100644 ---- a/testData/results/TestAmbiguousCall.dec -+++ b/testData/results/TestAmbiguousCall.dec -@@ -28,16 +28,38 @@ class 'pkg/TestAmbiguousCall' { - - method 'test ()V' { - 7 10 -+ 8 11 -+ 9 11 - a 11 -+ b 11 - c 11 -+ d 11 -+ e 11 -+ f 12 -+ 10 12 - 11 12 -+ 12 12 - 13 12 -+ 14 12 -+ 15 12 - 1d 13 -+ 1e 14 -+ 1f 14 - 20 14 -+ 21 14 - 22 14 -+ 23 14 -+ 24 14 -+ 25 15 -+ 26 15 - 27 15 -+ 28 15 -+ 29 15 - 2a 15 -+ 2b 15 - 2c 15 -+ 2d 15 -+ 2e 15 - 2f 16 - } - } -diff --git a/testData/results/TestAmbiguousCallWithDebugInfo.dec b/testData/results/TestAmbiguousCallWithDebugInfo.dec -index b697e795761f0f254e341663f4934e06ae3af8ef..e873e7e3cc488b036a46c332bd724e3fac30f720 100644 ---- a/testData/results/TestAmbiguousCallWithDebugInfo.dec -+++ b/testData/results/TestAmbiguousCallWithDebugInfo.dec -@@ -28,16 +28,38 @@ class 'pkg/TestAmbiguousCall' { - - method 'test ()V' { - 7 10 -+ 8 11 -+ 9 11 - a 11 -+ b 11 - c 11 -+ d 11 -+ e 11 -+ f 12 -+ 10 12 - 11 12 -+ 12 12 - 13 12 -+ 14 12 -+ 15 12 - 1d 13 -+ 1e 14 -+ 1f 14 - 20 14 -+ 21 14 - 22 14 -+ 23 14 -+ 24 14 -+ 25 15 -+ 26 15 - 27 15 -+ 28 15 -+ 29 15 - 2a 15 -+ 2b 15 - 2c 15 -+ 2d 15 -+ 2e 15 - 2f 16 - } - } -diff --git a/testData/results/TestAnonymousClass.dec b/testData/results/TestAnonymousClass.dec -index 3ea3c7058eadc696e538c72e018bd4076b07a397..044b1f23b7027c7317fba97b760993a45c70115d 100644 ---- a/testData/results/TestAnonymousClass.dec -+++ b/testData/results/TestAnonymousClass.dec -@@ -46,12 +46,12 @@ public abstract class TestAnonymousClass { - - void foo(int var1) throws Exception { - if (var1 > 0) {// 10 -- I var2 = new I() { -+ I var2 = new I() {// 11 - public void foo() throws Exception { - boolean var1 = true;// 13 - boolean var2 = true;// 14 - }// 15 -- };// 11 -+ }; - var2.foo();// 17 - } else { - System.out.println(5);// 21 -@@ -158,10 +158,18 @@ class 'pkg/TestAnonymousClass$1' { - - class 'pkg/TestAnonymousClass' { - method 'foo (I)V' { -+ 0 47 - 1 47 -- c 53 -+ c 48 -+ d 54 - e 54 -+ f 54 -+ 10 54 -+ 11 54 -+ 12 54 - 16 56 -+ 17 56 -+ 18 56 - 19 56 - 1a 56 - 1d 59 -@@ -192,7 +200,11 @@ class 'pkg/TestAnonymousClass$Inner$1' { - - class 'pkg/TestAnonymousClass$InnerRecursive' { - method ' (Lpkg/TestAnonymousClass$InnerRecursive;)V' { -+ 4 86 -+ 5 86 - 6 86 -+ 7 86 -+ 8 86 - 9 87 - } - -@@ -203,7 +215,7 @@ class 'pkg/TestAnonymousClass$InnerRecursive' { - - Lines mapping: - 10 <-> 48 --11 <-> 54 -+11 <-> 49 - 13 <-> 51 - 14 <-> 52 - 15 <-> 53 -diff --git a/testData/results/TestAnonymousClassConstructor.dec b/testData/results/TestAnonymousClassConstructor.dec -index e48e5bc934ccd1ed1aedd0fcde645026bbb4e3fe..08e25fc143aae82531a9e493c328a5606aef9f02 100644 ---- a/testData/results/TestAnonymousClassConstructor.dec -+++ b/testData/results/TestAnonymousClassConstructor.dec -@@ -117,139 +117,207 @@ class TestAnonymousClassConstructor { - class 'pkg/TestAnonymousClassConstructor' { - method 'innerPrivateString ()V' { - 5 4 -+ 6 4 - b 6 - } - - method 'innerPrivate ()V' { - 5 9 -+ 6 9 -+ 7 9 - 8 9 - d 11 - } - - method 'innerStaticPrivateString ()V' { - 5 14 -+ 6 14 - b 16 - } - - method 'innerStaticPrivate ()V' { - 5 19 -+ 6 19 -+ 7 19 - 8 19 - d 21 - } - - method 'innerStaticPrivateStringStatic ()V' { - 4 24 -+ 5 24 - a 26 - } - - method 'innerStaticPrivateStatic ()V' { - 4 29 -+ 5 29 -+ 6 29 - 7 29 - c 31 - } - - method 'innerPublicString ()V' { - 5 34 -+ 6 34 - b 36 - } - - method 'innerPublic ()V' { - 5 39 -+ 6 39 -+ 7 39 - 8 39 - d 41 - } - - method 'innerStaticPublicString ()V' { - 5 44 -+ 6 44 - b 46 - } - - method 'innerStaticPublic ()V' { - 5 49 -+ 6 49 -+ 7 49 - 8 49 - d 51 - } - - method 'innerStaticPublicStringStatic ()V' { - 4 54 -+ 5 54 - a 56 - } - - method 'innerStaticPublicStatic ()V' { - 4 59 -+ 5 59 -+ 6 59 - 7 59 - c 61 - } - - method 'n (Ljava/lang/String;)V' { - 0 64 -+ 1 64 -+ 2 64 - a 64 -+ b 64 -+ f 64 - 13 64 -+ 14 64 -+ 15 64 - 16 64 -+ 17 64 -+ 18 64 - 19 65 - } - } - - class 'pkg/TestAnonymousClassConstructor$InnerPrivate' { - method ' (Lpkg/TestAnonymousClassConstructor;JI)V' { -+ 10 69 - 14 69 -+ 15 69 -+ 19 69 -+ 1a 69 - 1e 69 -+ 1f 69 -+ 20 69 - 21 69 -+ 22 69 -+ 23 69 - 24 70 - } - } - - class 'pkg/TestAnonymousClassConstructor$InnerPrivateString' { - method ' (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' { -+ 9 75 - a 75 -+ b 75 -+ c 75 - d 76 - } - } - - class 'pkg/TestAnonymousClassConstructor$InnerPublic' { - method ' (Lpkg/TestAnonymousClassConstructor;JI)V' { -+ 10 81 - 14 81 -+ 15 81 -+ 19 81 -+ 1a 81 - 1e 81 -+ 1f 81 -+ 20 81 - 21 81 -+ 22 81 -+ 23 81 - 24 82 - } - } - - class 'pkg/TestAnonymousClassConstructor$InnerPublicString' { - method ' (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' { -+ 9 87 - a 87 -+ b 87 -+ c 87 - d 88 - } - } - - class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivate' { - method ' (JI)V' { -+ b 93 - f 93 -+ 10 93 -+ 14 93 - 18 93 -+ 19 93 -+ 1a 93 - 1b 93 -+ 1c 93 -+ 1d 93 - 1e 94 - } - } - - class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivateString' { - method ' (Ljava/lang/String;)V' { -+ 4 99 - 5 99 -+ 6 99 -+ 7 99 - 8 100 - } - } - - class 'pkg/TestAnonymousClassConstructor$InnerStaticPublic' { - method ' (JI)V' { -+ b 105 - f 105 -+ 10 105 -+ 14 105 - 18 105 -+ 19 105 -+ 1a 105 - 1b 105 -+ 1c 105 -+ 1d 105 - 1e 106 - } - } - - class 'pkg/TestAnonymousClassConstructor$InnerStaticPublicString' { - method ' (Ljava/lang/String;)V' { -+ 4 111 - 5 111 -+ 6 111 -+ 7 111 - 8 112 - } - } -diff --git a/testData/results/TestAnonymousParams.dec b/testData/results/TestAnonymousParams.dec -index c48794179eeaa512f49f552cdc691ee62c61adec..b963effed064e192a69c16c927a234a6708f68b2 100644 ---- a/testData/results/TestAnonymousParams.dec -+++ b/testData/results/TestAnonymousParams.dec -@@ -6,31 +6,38 @@ import java.io.InputStream; - - public class TestAnonymousParams { - void foo(InputStream in, final int a) throws IOException { -- FilterInputStream filterInputStream = new FilterInputStream(in) { -+ FilterInputStream filterInputStream = new FilterInputStream(in) {// 24 - public int read() throws IOException { - return a;// 27 - } -- };// 24 -+ }; - filterInputStream.read();// 30 - }// 31 - } - - class 'pkg/TestAnonymousParams$1' { - method 'read ()I' { -+ 1 10 -+ 2 10 -+ 3 10 - 4 10 - } - } - - class 'pkg/TestAnonymousParams' { - method 'foo (Ljava/io/InputStream;I)V' { -- a 12 -+ 5 8 -+ a 8 -+ b 13 - c 13 -+ d 13 -+ e 13 - 10 14 - } - } - - Lines mapping: --24 <-> 13 -+24 <-> 9 - 27 <-> 11 - 30 <-> 14 - 31 <-> 15 -diff --git a/testData/results/TestAnonymousSignature.dec b/testData/results/TestAnonymousSignature.dec -index 95ad203e3412f03b51eb06a9f926586f653042de..0c183ba28589c504aafed9631bea09e6524ae19d 100644 ---- a/testData/results/TestAnonymousSignature.dec -+++ b/testData/results/TestAnonymousSignature.dec -@@ -21,6 +21,8 @@ public class TestAnonymousSignature { - class 'pkg/TestAnonymousSignature$1' { - method 'size ()I' { - 1 9 -+ 2 9 -+ 3 9 - 4 9 - } - } -@@ -35,9 +37,17 @@ class 'pkg/TestAnonymousSignature$2' { - class 'pkg/TestAnonymousSignature' { - method 'main ([Ljava/lang/String;)V' { - 0 7 -+ 1 7 -+ 2 7 - a 7 -+ b 7 -+ c 7 - d 12 -+ e 12 -+ f 12 - 17 12 -+ 18 12 -+ 19 12 - 1a 17 - } - } -diff --git a/testData/results/TestAsserts.dec b/testData/results/TestAsserts.dec -index f260d9efcbc1332056ce9b534d56a3305fbd4bf1..c9e51a54a63c5615a5e6b03ef1e256b8067233e9 100644 ---- a/testData/results/TestAsserts.dec -+++ b/testData/results/TestAsserts.dec -@@ -16,10 +16,13 @@ class 'pkg/TestAsserts' { - method 'foo ()I' { - 0 4 - 1 4 -+ 8 6 - 9 6 - a 6 -+ 1b 8 - 1c 8 - 1d 8 -+ 20 8 - 21 8 - 22 8 - 2d 10 -diff --git a/testData/results/TestClashName.dec b/testData/results/TestClashName.dec -index 2a9a731549e4bee8fe6ff812211e5a7930252017..9adf65e9646db3f5243ab2ead6806f502cfea1bb 100644 ---- a/testData/results/TestClashName.dec -+++ b/testData/results/TestClashName.dec -@@ -63,19 +63,39 @@ class 'pkg/TestClashName' { - } - - method 'm ()I' { -- 1 31 -- 4 31 -- 6 32 -- 9 32 -- c 33 -- f 33 -- 11 34 -- 14 34 -- 17 35 -- 1a 35 -- 1d 36 -- 1f 36 -- 20 36 -+ 0 20 -+ 1 20 -+ 2 20 -+ 3 20 -+ 4 20 -+ 5 21 -+ 6 21 -+ 7 21 -+ 8 21 -+ 9 21 -+ a 21 -+ b 21 -+ c 22 -+ d 22 -+ e 22 -+ f 22 -+ 10 23 -+ 11 23 -+ 12 23 -+ 13 23 -+ 14 23 -+ 15 23 -+ 16 23 -+ 17 24 -+ 18 24 -+ 19 24 -+ 1a 24 -+ 1b 25 -+ 1c 25 -+ 1d 25 -+ 1e 25 -+ 1f 25 -+ 20 25 - } - - method 'f ()V' { -diff --git a/testData/results/TestClassCast.dec b/testData/results/TestClassCast.dec -index e807294b770fefe3a7ea25c77e7b962b65e345f9..f602eea1b4bd4eb097a41992cd3271020a15c2c5 100644 ---- a/testData/results/TestClassCast.dec -+++ b/testData/results/TestClassCast.dec -@@ -16,14 +16,29 @@ public class TestClassCast { - - class 'pkg/TestClassCast' { - method 'test (Ljava/util/List;)V' { -+ 0 7 - 1 7 - 3 8 - f 9 - 10 9 -+ 11 9 - 12 9 -+ 13 9 -+ 14 9 -+ 15 9 -+ 16 9 - 18 12 -+ 19 12 -+ 1a 12 -+ 1b 12 - 1c 12 -+ 1d 12 -+ 1e 12 -+ 1f 12 -+ 20 12 - 21 12 -+ 22 12 -+ 23 12 - 24 13 - } - } -diff --git a/testData/results/TestClassFields.dec b/testData/results/TestClassFields.dec -index ea272ead5c52deca629cb12876748960044559e0..4c37124913d759059ccf151547cfd163d6342412 100644 ---- a/testData/results/TestClassFields.dec -+++ b/testData/results/TestClassFields.dec -@@ -19,12 +19,13 @@ public class TestClassFields { - class 'pkg/TestClassFields' { - method ' ()V' { - 11 8 -+ 12 8 -+ 13 8 - 14 8 - 17 8 -- 1b 9 -- 1f 10 -- 22 10 -- 25 11 -+ 18 8 -+ 19 8 -+ 20 9 - } - } - -diff --git a/testData/results/TestClassLambda.dec b/testData/results/TestClassLambda.dec -index cae1518889f1af8977a574de616e37574b3b2c16..9bb7d48e1531f3ac1e467ba8eac25de08b4da3da 100644 ---- a/testData/results/TestClassLambda.dec -+++ b/testData/results/TestClassLambda.dec -@@ -22,12 +22,12 @@ public class TestClassLambda { - - public void testLambda1() { - int var1 = (int)Math.random();// 39 -- Runnable var2 = () -> { -+ Runnable var2 = () -> {// 40 - System.out.println("hello1" + var1); -- };// 40 -- Runnable var3 = () -> { -+ }; -+ Runnable var3 = () -> {// 41 - System.out.println("hello2" + var1); -- };// 41 -+ }; - }// 42 - - public void testLambda2() { -@@ -76,51 +76,88 @@ public class TestClassLambda { - - public void nestedLambdas() { - byte var1 = 5;// 85 -- Runnable var2 = () -> { -- Runnable var1x = () -> { -+ Runnable var2 = () -> {// 86 -+ Runnable var1x = () -> {// 87 - System.out.println("hello2" + var1); -- };// 87 -+ }; - System.out.println("hello1" + var1);// 88 -- };// 86 89 -+ };// 89 - }// 90 - } - - class 'pkg/TestClassLambda' { - method 'lambda$testLambda$0 (ILjava/lang/Integer;)V' { -- 0 17 -- 2 17 -- 5 17 -- 6 17 -- 7 18 -- c 18 -- e 18 -- 11 18 -- 12 18 -- 15 19 -+ 0 20 -+ 1 20 -+ 2 20 -+ 3 20 -+ 4 20 -+ 5 20 -+ 6 20 -+ 7 21 -+ 8 21 -+ 9 21 -+ a 21 -+ b 21 -+ c 21 -+ d 21 -+ e 21 -+ f 21 -+ 10 21 -+ 11 21 -+ 12 21 -+ 13 21 -+ 14 21 -+ 15 22 - } - - method 'testLambda ()V' { -- 7 14 -- 8 14 -- e 14 -- f 14 -- 15 14 -- 16 14 -- 1c 14 -- 1d 14 -- 23 14 -- 24 14 -- 2a 14 -- 2c 14 -- 33 14 -- 35 14 -- 39 14 -- 3c 14 -- 3d 15 -- 40 15 -- 41 15 -- 4a 16 -- 4f 20 -+ 7 17 -+ 8 17 -+ 9 17 -+ a 17 -+ e 17 -+ f 17 -+ 10 17 -+ 11 17 -+ 15 17 -+ 16 17 -+ 17 17 -+ 18 17 -+ 1c 17 -+ 1d 17 -+ 1e 17 -+ 1f 17 -+ 23 17 -+ 24 17 -+ 25 17 -+ 26 17 -+ 2a 17 -+ 2b 17 -+ 2c 17 -+ 2d 17 -+ 2e 17 -+ 33 17 -+ 34 17 -+ 35 17 -+ 36 17 -+ 37 17 -+ 39 17 -+ 3a 17 -+ 3b 17 -+ 3c 17 -+ 3d 18 -+ 3e 18 -+ 3f 18 -+ 40 18 -+ 41 18 -+ 42 19 -+ 4a 19 -+ 4b 19 -+ 4c 19 -+ 4d 19 -+ 4e 19 -+ 4f 23 - } - - method 'lambda$testLambda1$1 (I)V' { -@@ -133,74 +170,143 @@ class 'pkg/TestClassLambda' { - - method 'lambda$testLambda1$2 (I)V' { - 0 28 -+ 1 28 -+ 2 28 - a 28 -+ b 28 -+ f 28 - 13 28 -+ 14 28 -+ 15 28 - 16 28 -+ 17 28 -+ 18 28 - 19 29 - } - -+ method 'lambda$testLambda1$2 (I)V' { -+ 0 31 -+ 1 31 -+ 2 31 -+ a 31 -+ b 31 -+ f 31 -+ 13 31 -+ 14 31 -+ 15 31 -+ 16 31 -+ 17 31 -+ 18 31 -+ 19 32 -+ } -+ - method 'testLambda1 ()V' { -- 0 23 -- 3 23 -- 4 23 -- b 26 -- 12 29 -- 13 30 -+ 0 26 -+ 1 26 -+ 2 26 -+ 3 26 -+ 4 26 -+ b 27 -+ 12 30 -+ 13 33 - } - - method 'lambda$testLambda2$3 (II)I' { -- 2 34 -- 5 34 -+ 0 37 -+ 1 37 -+ 2 37 -+ 3 37 -+ 4 37 -+ 5 37 - } - - method 'testLambda2 ()V' { -- 5 33 -- 9 36 -+ 5 36 -+ 6 36 -+ 7 36 -+ 9 39 - } - - method 'testLambda3 ()V' { -- 5 39 -- 9 40 -+ 5 42 -+ 6 42 -+ 7 42 -+ 9 43 - } - - method 'testLambda4 ()V' { -- 5 43 -- 9 44 -+ 5 46 -+ 6 46 -+ 7 46 -+ 9 47 - } - - method 'testLambda5 ()V' { -- 0 47 -- 2 47 -- e 48 -- 12 49 -+ 0 50 -+ 1 50 -+ 2 50 -+ e 51 -+ f 51 -+ 10 51 -+ 12 52 - } - - method 'lambda$testLambda6$4 (IILjava/lang/String;)Z' { -- 2 56 -- 5 56 -- 9 56 -- d 56 -- 15 56 -+ 0 59 -+ 1 59 -+ 2 59 -+ 3 59 -+ 4 59 -+ 5 59 -+ 8 59 -+ 9 59 -+ a 59 -+ b 59 -+ c 59 -+ d 59 -+ 15 59 - } - - method 'testLambda6 ()V' { -- 7 52 -- 9 53 -- e 53 -- f 53 -- 10 53 -- 12 54 -- 17 54 -- 18 54 -- 19 54 -- 22 55 -- 28 58 -+ 7 55 -+ 8 56 -+ 9 56 -+ a 56 -+ b 56 -+ c 56 -+ d 56 -+ e 56 -+ f 56 -+ 10 56 -+ 11 57 -+ 12 57 -+ 13 57 -+ 14 57 -+ 15 57 -+ 16 57 -+ 17 57 -+ 18 57 -+ 19 57 -+ 1a 58 -+ 22 58 -+ 23 58 -+ 24 58 -+ 25 58 -+ 26 58 -+ 28 61 - } - - method 'testLambda7 ([Ljava/lang/annotation/Annotation;)V' { -- 1 61 -- 9 61 -- f 62 -+ 0 64 -+ 1 64 -+ 2 64 -+ 3 64 -+ 9 64 -+ a 64 -+ b 64 -+ c 64 -+ d 64 -+ f 65 - } - - method 'reduce (Ljava/util/function/IntBinaryOperator;)Ljava/util/OptionalInt;' { -@@ -209,9 +315,16 @@ class 'pkg/TestClassLambda' { - } - - method 'function (Ljava/util/function/Supplier;)Ljava/lang/String;' { -- 1 69 -- 6 69 -- 9 69 -+ 0 72 -+ 1 72 -+ 2 72 -+ 3 72 -+ 4 72 -+ 5 72 -+ 6 72 -+ 7 72 -+ 8 72 -+ 9 72 - } - - method 'localMax (II)I' { -@@ -220,64 +333,80 @@ class 'pkg/TestClassLambda' { - } - - method 'lambda$null$5 (I)V' { -- 0 80 -- a 80 -- 13 80 -- 16 80 -- 19 81 -+ 0 83 -+ 1 83 -+ 2 83 -+ a 83 -+ b 83 -+ f 83 -+ 13 83 -+ 14 83 -+ 15 83 -+ 16 83 -+ 17 83 -+ 18 83 -+ 19 84 - } - - method 'lambda$nestedLambdas$6 (I)V' { -- 6 81 -- 7 82 -- 11 82 -- 1a 82 -- 1d 82 -- 20 83 -+ 6 82 -+ 7 85 -+ 8 85 -+ 9 85 -+ 11 85 -+ 12 85 -+ 16 85 -+ 1a 85 -+ 1b 85 -+ 1c 85 -+ 1d 85 -+ 1e 85 -+ 1f 85 -+ 20 86 - } - - method 'nestedLambdas ()V' { -- 0 77 -- 1 77 -- 8 83 -- 9 84 -+ 0 80 -+ 1 80 -+ 8 81 -+ 9 87 - } - } - - Lines mapping: --29 <-> 15 --30 <-> 16 --32 <-> 17 --33 <-> 18 --34 <-> 19 --35 <-> 20 --36 <-> 21 --39 <-> 24 --40 <-> 27 --41 <-> 30 --42 <-> 31 --45 <-> 34 --46 <-> 37 --49 <-> 40 --50 <-> 41 --53 <-> 44 --54 <-> 45 --57 <-> 48 --58 <-> 49 --59 <-> 50 --62 <-> 53 --63 <-> 54 --64 <-> 55 --65 <-> 56 --66 <-> 59 --69 <-> 62 --70 <-> 63 --73 <-> 66 --77 <-> 70 --81 <-> 74 --85 <-> 78 --86 <-> 84 --87 <-> 82 --88 <-> 83 --89 <-> 84 --90 <-> 85 -+29 <-> 18 -+30 <-> 19 -+32 <-> 20 -+33 <-> 21 -+34 <-> 22 -+35 <-> 23 -+36 <-> 24 -+39 <-> 27 -+40 <-> 28 -+41 <-> 31 -+42 <-> 34 -+45 <-> 37 -+46 <-> 40 -+49 <-> 43 -+50 <-> 44 -+53 <-> 47 -+54 <-> 48 -+57 <-> 51 -+58 <-> 52 -+59 <-> 53 -+62 <-> 56 -+63 <-> 57 -+64 <-> 58 -+65 <-> 59 -+66 <-> 62 -+69 <-> 65 -+70 <-> 66 -+73 <-> 69 -+77 <-> 73 -+81 <-> 77 -+85 <-> 81 -+86 <-> 82 -+87 <-> 83 -+88 <-> 86 -+89 <-> 87 -+90 <-> 88 -diff --git a/testData/results/TestClassLoop.dec b/testData/results/TestClassLoop.dec -index 4c2e9ff65a838ba16edbb9a178d11a0c3f85841a..137a4edd73da81f3150da42957bbaa266321a69f 100644 ---- a/testData/results/TestClassLoop.dec -+++ b/testData/results/TestClassLoop.dec -@@ -78,41 +78,68 @@ public class TestClassLoop { - class 'pkg/TestClassLoop' { - method 'testSimpleInfinite ()V' { - 0 5 -+ 1 5 -+ 2 5 - 3 5 -+ 4 5 -+ 5 5 - } - - method 'testFinally ()V' { - 0 10 -+ 1 10 -+ 2 10 - 3 10 - 4 10 - d 10 -+ e 14 - f 14 - 1a 15 - 26 18 - 27 18 -+ 28 18 -+ 29 18 - 2a 18 -+ 2b 18 - } - - method 'testFinallyContinue ()V' { - 0 24 -+ 1 24 -+ 2 24 - 3 24 - 4 24 - d 24 - e 29 -+ f 29 -+ 10 29 - 11 29 -+ 12 29 - 13 29 -+ 25 32 - 26 32 - 2a 33 -+ 2b 33 -+ 2c 33 - 2d 33 -+ 2e 33 - 2f 33 -+ 30 33 -+ 31 33 - 32 34 - 37 39 -+ 38 39 -+ 39 39 - 3a 39 -+ 3b 39 - 3c 39 - } - - method 'testWhileCombined (Ljava/lang/String;)I' { -+ 0 44 - 1 44 -+ 2 44 -+ 3 44 - 4 44 - 5 45 - 6 45 -@@ -120,29 +147,58 @@ class 'pkg/TestClassLoop' { - 8 46 - 9 47 - a 47 -+ b 47 - c 48 - d 48 -+ e 48 - f 49 - 10 49 -+ 11 49 - 12 51 - 13 51 -+ 14 51 -+ 15 51 -+ 16 51 - 17 51 -+ 1a 52 -+ 1b 52 - 1c 52 -+ 1d 52 -+ 1e 52 - 1f 52 -+ 20 52 -+ 21 53 -+ 22 53 - 23 53 -+ 24 53 - 25 53 - 28 54 -+ 29 54 -+ 2a 54 -+ 2e 56 -+ 2f 56 - 30 56 -+ 31 56 - 32 56 -+ 35 60 - 36 60 - 3d 61 -+ 3e 61 - 42 61 -+ 43 64 - 44 64 -+ 45 64 -+ 46 65 -+ 47 65 - 48 65 - 4b 66 - 4e 69 - 4f 69 - 50 51 -+ 51 51 -+ 52 51 -+ 56 73 -+ 57 73 - 58 73 - } - } -diff --git a/testData/results/TestClassNestedInitializer.dec b/testData/results/TestClassNestedInitializer.dec -index 0576e74a1d8f22a9dee2d72ba7dc984e269abe9d..f2617df3c17a6b9caa908148f7d612a498ed9eee 100644 ---- a/testData/results/TestClassNestedInitializer.dec -+++ b/testData/results/TestClassNestedInitializer.dec -@@ -4,34 +4,45 @@ public class TestClassNestedInitializer { - public String secret; - - public void test() { -- TestClassNestedInitializer var1 = new TestClassNestedInitializer() { -+ TestClassNestedInitializer var1 = new TestClassNestedInitializer() {// 22 - { - this.secret = "one"; - } -- };// 22 -+ }; - System.out.println(var1.secret);// 23 - }// 24 - } - - class 'pkg/TestClassNestedInitializer$1' { - method ' (Lpkg/TestClassNestedInitializer;)V' { -+ 9 8 - a 8 -+ b 8 - c 8 -+ d 8 -+ e 8 - f 9 - } - } - - class 'pkg/TestClassNestedInitializer' { - method 'test ()V' { -- 8 10 -+ 8 6 - 9 11 -+ a 11 -+ b 11 -+ c 11 - d 11 -+ e 11 -+ f 11 - 10 11 -+ 11 11 -+ 12 11 - 13 12 - } - } - - Lines mapping: --22 <-> 11 -+22 <-> 7 - 23 <-> 12 - 24 <-> 13 -diff --git a/testData/results/TestClassSimpleBytecodeMapping.dec b/testData/results/TestClassSimpleBytecodeMapping.dec -index 7c03120a91f0fc0a5cecbbff4cd7b2c0d0da2c94..706965c11a037c3dd1726371d6b9bd9224269ddb 100644 ---- a/testData/results/TestClassSimpleBytecodeMapping.dec -+++ b/testData/results/TestClassSimpleBytecodeMapping.dec -@@ -49,8 +49,13 @@ public class TestClassSimpleBytecodeMapping { - class 'pkg/TestClassSimpleBytecodeMapping$1' { - method 'run ()V' { - 0 7 -+ 1 7 -+ 2 7 - 3 7 -+ 4 7 - 5 7 -+ 6 7 -+ 7 7 - 8 8 - } - } -@@ -58,40 +63,77 @@ class 'pkg/TestClassSimpleBytecodeMapping$1' { - class 'pkg/TestClassSimpleBytecodeMapping' { - method 'test ()I' { - 0 4 -+ 1 4 -+ 2 4 - 3 4 -+ 4 4 - 5 4 -+ 6 4 -+ 7 4 -+ 8 5 - 11 5 -+ 12 5 -+ 13 5 -+ 14 10 - 15 10 -+ 16 10 - 17 10 -+ 18 10 -+ 19 10 - 1a 11 -+ 1b 11 -+ 1c 11 - 1d 11 - 1e 11 - 1f 11 - 22 12 -+ 23 12 -+ 24 12 - 25 12 -+ 26 12 - 27 12 -+ 28 12 -+ 29 12 - 2a 13 - 2b 13 - 2c 15 -+ 2d 15 -+ 2e 15 - 2f 15 -+ 30 15 - 31 15 -+ 32 15 -+ 33 15 - 34 16 - 35 16 - } - - method 'test2 (Ljava/lang/String;)V' { -+ 0 22 - 1 22 -+ 2 22 -+ 3 22 - 10 23 - 11 24 -+ 12 24 -+ 13 24 - 15 24 - 23 26 - 24 26 -+ 25 26 -+ 26 26 - 27 26 -+ 28 26 - 2e 29 - } - - method 'run (Ljava/lang/Runnable;)V' { -+ 0 32 - 1 32 -+ 2 32 -+ 3 32 -+ 4 32 -+ 5 32 - 6 33 - } - } -@@ -99,8 +141,13 @@ class 'pkg/TestClassSimpleBytecodeMapping' { - class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' { - method 'print ()V' { - 0 37 -+ 1 37 -+ 2 37 - 3 37 -+ 4 37 - 5 37 -+ 6 37 -+ 7 37 - 8 38 - } - } -@@ -108,8 +155,13 @@ class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' { - class 'pkg/TestClassSimpleBytecodeMapping$InnerClass2' { - method 'print ()V' { - 0 43 -+ 1 43 -+ 2 43 - 3 43 -+ 4 43 - 5 43 -+ 6 43 -+ 7 43 - 8 44 - } - } -diff --git a/testData/results/TestClassSwitch.dec b/testData/results/TestClassSwitch.dec -index 3f42b35767b44c7cb2b0eaf31dbbf61d9c3b315a..6a2b156f9ad0e29aad668542ee090d63130d2182 100644 ---- a/testData/results/TestClassSwitch.dec -+++ b/testData/results/TestClassSwitch.dec -@@ -15,12 +15,20 @@ public class TestClassSwitch { - - class 'pkg/TestClassSwitch' { - method 'testCaseOrder (I)V' { -+ 0 4 - 1 4 - 1c 10 -+ 1d 10 -+ 1e 10 - 1f 10 -+ 20 10 - 21 10 -+ 22 10 -+ 23 10 - 24 12 - 25 6 -+ 26 6 -+ 27 6 - 28 6 - 29 6 - 2c 8 -diff --git a/testData/results/TestClassTypes.dec b/testData/results/TestClassTypes.dec -index 07980cc103b3434bdefc78de045120dd6babaa51..a90e113aaabede0b4df7e1e8bcd9f06699a8e061 100644 ---- a/testData/results/TestClassTypes.dec -+++ b/testData/results/TestClassTypes.dec -@@ -53,29 +53,41 @@ class 'pkg/TestClassTypes' { - 0 7 - 1 7 - 2 8 -+ 3 8 -+ 4 8 - 5 8 -+ 6 9 - 7 9 -+ 8 9 -+ 9 9 - a 9 - b 9 - c 9 - d 9 - 10 10 - 11 10 -+ 15 11 - 16 11 -+ 17 11 -+ 18 11 - 19 11 - 1a 11 - 1b 11 - 1c 11 - 1f 12 - 20 12 -+ 21 15 - 22 15 - 23 15 - 26 16 -+ 27 16 -+ 28 16 - 29 16 - 2c 19 - } - - method 'testBit (I)Z' { -+ 0 22 - 1 22 - 2 22 - 3 22 -@@ -84,30 +96,59 @@ class 'pkg/TestClassTypes' { - } - - method 'testSwitchConsts (I)V' { -+ 0 26 - 1 26 - 2c 28 -+ 2d 28 -+ 2e 28 - 2f 28 -+ 30 28 - 31 28 -+ 32 28 -+ 33 28 - 34 29 - 37 31 -+ 38 31 -+ 39 31 - 3a 31 -+ 3b 31 - 3c 31 -+ 3d 31 -+ 3e 31 - 3f 32 - 42 35 -+ 43 35 -+ 44 35 - 45 35 -+ 46 35 - 47 35 - 4a 38 - } - - method 'testAssignmentType (Ljava/util/List;)V' { -+ 0 41 - 1 41 - 3 42 - f 43 - 10 43 -+ 11 43 - 12 43 -+ 13 43 -+ 14 43 -+ 15 43 -+ 16 43 - 18 46 -+ 19 46 -+ 1a 46 -+ 1b 46 - 1c 46 -+ 1d 46 -+ 1e 46 -+ 1f 46 -+ 20 46 - 21 46 -+ 22 46 -+ 23 46 - 24 47 - } - } -diff --git a/testData/results/TestClassVar.dec b/testData/results/TestClassVar.dec -index 9beaab18d63a04c8da209347ef10ffdd32dd6800..6de2af6b7b05a4e6c53c7fd9103e0baf839548d2 100644 ---- a/testData/results/TestClassVar.dec -+++ b/testData/results/TestClassVar.dec -@@ -42,20 +42,32 @@ class 'pkg/TestClassVar' { - method 'testFieldSSAU ()V' { - 0 7 - 1 7 -+ 2 7 - 3 7 -+ 4 7 - 5 7 - 8 9 -+ 9 9 -+ a 9 - b 9 -+ 1e 11 - 1f 11 - 20 11 -+ 21 11 -+ 22 11 - 26 12 -+ 27 12 -+ 28 12 - 29 12 - 2e 7 - 34 18 - } - - method 'testFieldSSAU1 ()Ljava/lang/Long;' { -+ 4 21 - 6 21 -+ 7 21 -+ 8 21 - b 21 - f 21 - 13 21 -@@ -64,17 +76,29 @@ class 'pkg/TestClassVar' { - method 'testComplexPropagation ()V' { - 0 25 - 1 25 -+ 2 27 - 3 27 -+ 4 27 - 5 27 -+ 8 29 - 9 29 -+ a 29 - b 29 -+ c 29 - d 29 -+ 10 29 - 11 29 - 14 29 -- 1c 32 -- 1f 33 -- 22 33 -- 28 37 -+ 15 29 -+ 16 29 -+ 1a 33 -+ 1b 33 -+ 1c 33 -+ 1f 34 -+ 20 34 -+ 21 34 -+ 22 34 -+ 28 38 - } - } - -diff --git a/testData/results/TestCodeConstructs.dec b/testData/results/TestCodeConstructs.dec -index fefd4212a729bcafc87860b0ed02969149e019f7..2e422b84f097ceb4f923d2cafe9a0c84c1302881 100644 ---- a/testData/results/TestCodeConstructs.dec -+++ b/testData/results/TestCodeConstructs.dec -@@ -15,11 +15,16 @@ class TestCodeConstructs { - class 'pkg/TestCodeConstructs' { - method 'expressions ()V' { - 7 6 -+ 8 6 -+ 9 6 - b 7 - } - - method 'fieldIncrement ()Ljava/lang/Integer;' { -+ 4 10 - 6 10 -+ 7 10 -+ 8 10 - b 10 - 12 10 - } -diff --git a/testData/results/TestDebugSymbols.dec b/testData/results/TestDebugSymbols.dec -index 1010becabda4cb15ee6daeba50f2c4935aefa56d..a405885e6b5a53c8cefbfe9db0f045d562e43d42 100644 ---- a/testData/results/TestDebugSymbols.dec -+++ b/testData/results/TestDebugSymbols.dec -@@ -23,22 +23,44 @@ class TestDebugSymbols { - class 'pkg/TestDebugSymbols' { - method 'm ()I' { - 0 4 -+ 1 4 - 2 4 - 3 5 -+ 4 5 -+ 5 5 - 6 5 -+ 7 6 - 8 6 - 9 6 -+ a 6 - b 6 - c 6 -+ d 6 - e 7 -+ f 7 -+ 10 7 - 11 7 - 12 7 - 13 7 -+ 14 7 -+ 1c 8 - 20 8 -+ 21 8 -+ 25 8 - 29 8 -+ 2a 8 -+ 2e 8 -+ 2f 8 - 33 8 -+ 34 8 -+ 38 8 -+ 39 8 - 3d 8 -+ 3e 8 -+ 3f 8 - 40 8 -+ 41 8 -+ 42 8 - 43 8 - } - -diff --git a/testData/results/TestEnum.dec b/testData/results/TestEnum.dec -index 40f54d7f0c4ce8b4984d26fac0b13aa1d1dfb145..5248b0236ee49381488c6c5fd3ca8efd4571ba0e 100644 ---- a/testData/results/TestEnum.dec -+++ b/testData/results/TestEnum.dec -@@ -50,13 +50,20 @@ class 'pkg/TestEnum' { - - method ' (Ljava/lang/String;I)V' { - 3 20 -+ 4 20 - 5 20 - 6 20 -+ 7 20 -+ 8 20 - 9 21 - } - - method ' (Ljava/lang/String;ILjava/lang/String;Lpkg/TestEnum$Type;)V' { -+ 6 24 -+ 7 24 - 8 24 -+ 9 24 -+ a 24 - b 25 - } - } -diff --git a/testData/results/TestExtendingSubclass.dec b/testData/results/TestExtendingSubclass.dec -index 6bab8435926e1c10171fc97b61075ec58dba2572..b9e66bb809b5c7c37a5c04dd08e074e5e3c607b2 100644 ---- a/testData/results/TestExtendingSubclass.dec -+++ b/testData/results/TestExtendingSubclass.dec -@@ -21,7 +21,10 @@ class 'pkg/TestExtendingSubclass$Subclass1' { - - class 'pkg/TestExtendingSubclass$Subclass2' { - method ' (Lpkg/TestExtendingSubclass;Ljava/lang/String;)V' { -+ 7 10 - 8 10 -+ 9 10 -+ a 10 - b 11 - } - } -diff --git a/testData/results/TestIffSimplification.dec b/testData/results/TestIffSimplification.dec -index 0c3a1c421353fe2b9c3f652d999a2c26633511e4..1598c234401e462f4a189cf17bcf3e13c5fbda1b 100644 ---- a/testData/results/TestIffSimplification.dec -+++ b/testData/results/TestIffSimplification.dec -@@ -32,54 +32,91 @@ public class TestIffSimplification { - - class 'pkg/TestIffSimplification' { - method 'simpleIff (Z[I)I' { -+ 0 4 - 1 4 -+ 4 4 - 5 4 - 6 4 -+ a 4 - b 4 - c 4 - d 4 - } - - method 'simpleIf (Z[I)I' { -+ 0 8 - 1 8 -+ 4 8 - 5 8 - 6 8 -+ 8 8 - 9 8 - a 8 - } - - method 'nestedIf (ZZ[I)I' { -+ 0 12 - 1 12 -+ 4 13 - 5 13 -+ 8 13 - 9 13 - a 13 -+ c 13 - d 13 - e 13 -+ 10 15 - 11 15 - 12 15 - 13 15 - } - - method 'compareTo (IIBBDDII)I' { -+ 0 20 -+ 1 20 - 2 20 -+ 5 21 -+ 6 21 - 7 21 - a 21 - e 21 - f 21 -+ 10 22 -+ 11 22 -+ 12 22 - 13 22 -+ 16 23 -+ 17 23 -+ 18 23 - 19 23 - 1c 23 - 20 23 - 21 23 -+ 22 24 -+ 23 24 -+ 24 24 -+ 25 24 - 26 24 - 27 24 -+ 28 24 -+ 29 24 - 2a 24 -+ 2b 24 -+ 2c 24 - 2d 24 - 2e 24 -+ 31 25 -+ 32 25 -+ 33 25 -+ 34 25 - 35 25 - 38 25 - 3c 25 - 3d 25 -+ 3e 27 -+ 3f 27 -+ 40 27 -+ 41 27 - 42 27 - 43 27 - 46 27 -diff --git a/testData/results/TestIllegalVarName.dec b/testData/results/TestIllegalVarName.dec -index 3eb1ea54a6080827d3022ea409fdbdc84febf881..5178d8421eb80d2f354cf156bb0ada67c8093d19 100644 ---- a/testData/results/TestIllegalVarName.dec -+++ b/testData/results/TestIllegalVarName.dec -@@ -21,10 +21,19 @@ public final class TestIllegalVarName { - - class 'pkg/TestIllegalVarName' { - method 'm (Ljava/lang/String;I)Ljava/lang/String;' { -+ 0 16 - 1 16 -+ 2 16 - 3 16 -+ 4 16 -+ 5 16 -+ d 17 - 11 17 -+ 12 17 -+ 16 17 - 1a 17 -+ 1b 17 -+ 1c 17 - 1d 17 - } - } -diff --git a/testData/results/TestInnerClassConstructor.dec b/testData/results/TestInnerClassConstructor.dec -index e37f5014eb173ea82ba61f3a863cc7b5c2ff936b..99ab820bb84ed0fb45bcc7a92dd6c371de0eaa91 100644 ---- a/testData/results/TestInnerClassConstructor.dec -+++ b/testData/results/TestInnerClassConstructor.dec -@@ -29,6 +29,7 @@ class TestInnerClassConstructor { - class 'pkg/TestInnerClassConstructor' { - method 'l ()V' { - 5 4 -+ 6 4 - c 5 - } - -@@ -40,25 +41,45 @@ class 'pkg/TestInnerClassConstructor' { - - method 'n (Ljava/lang/String;)V' { - 0 12 -+ 1 12 -+ 2 12 - a 12 -+ b 12 -+ f 12 - 13 12 -+ 14 12 -+ 15 12 - 16 12 -+ 17 12 -+ 18 12 - 19 13 - } - } - - class 'pkg/TestInnerClassConstructor$Another' { - method ' (Lpkg/TestInnerClassConstructor;II)V' { -+ 9 17 -+ 11 17 - 15 17 -+ 16 17 -+ 1a 17 - 1e 17 -+ 1f 17 -+ 20 17 - 21 17 -+ 22 17 -+ 23 17 - 24 18 - } - } - - class 'pkg/TestInnerClassConstructor$Inner' { - method ' (Lpkg/TestInnerClassConstructor;Ljava/lang/String;)V' { -+ 9 23 -+ a 23 - b 23 -+ c 23 -+ d 23 - e 24 - } - } -diff --git a/testData/results/TestInnerLocal.dec b/testData/results/TestInnerLocal.dec -index 9009b85453ba2aae2ac4e32f94fb082dcd6d3c81..cf53952d828695bf661720d580e84c4d07273299 100644 ---- a/testData/results/TestInnerLocal.dec -+++ b/testData/results/TestInnerLocal.dec -@@ -57,52 +57,79 @@ public class TestInnerLocal { - - class 'pkg/TestInnerLocal$1Inner' { - method ' (Ljava/lang/String;)V' { -- 6 8 -- 9 9 -+ 4 6 -+ 5 6 -+ 6 6 -+ 7 6 -+ 8 6 -+ 9 7 - } - } - - class 'pkg/TestInnerLocal' { - method 'testStaticMethod ()V' { -- 4 12 -- e 13 -- 18 14 -- 1e 15 -+ 4 10 -+ 5 10 -+ e 11 -+ f 11 -+ 18 12 -+ 19 12 -+ 1e 13 - } - - method 'testMethod ()V' { -- 5 26 -- f 27 -- 1a 28 -- 24 29 -- 2a 30 -+ 5 24 -+ 6 24 -+ f 25 -+ 10 25 -+ 1a 26 -+ 1b 26 -+ 24 27 -+ 25 27 -+ 2a 28 - } - } - --class 'pkg/TestInnerLocal$2Inner' { -- method ' (Lpkg/TestInnerLocal;Ljava/lang/String;)V' { -- b 22 -- e 23 -+class 'TestInnerLocal$2Inner' { -+ method ' (LTestInnerLocal;Ljava/lang/String;)V' { -+ 9 20 -+ a 20 -+ b 20 -+ c 20 -+ d 20 -+ e 21 - } - } - - class 'TestInnerLocal$Inner1' { - method ' (LTestInnerLocal;Ljava/lang/String;)V' { -+ 9 34 -+ a 34 - b 34 -+ c 34 -+ d 34 - e 35 - } - } - - class 'TestInnerLocal$Inner1Static' { - method ' (Ljava/lang/String;)V' { -+ 4 42 -+ 5 42 - 6 42 -+ 7 42 -+ 8 42 - 9 43 - } - } - - class 'pkg/TestInnerLocal$Inner1Static$Inner2Static' { - method ' (Ljava/lang/String;)V' { -+ 4 49 -+ 5 49 - 6 49 -+ 7 49 -+ 8 49 - 9 50 - } - } -diff --git a/testData/results/TestInnerSignature.dec b/testData/results/TestInnerSignature.dec -index 8aab3c2b9f56368f1350f1ac98262c761bf6ed19..37b216917552fc933ebc5fa3239002fa2b52d575 100644 ---- a/testData/results/TestInnerSignature.dec -+++ b/testData/results/TestInnerSignature.dec -@@ -38,27 +38,64 @@ public class TestInnerSignature { - - class 'pkg/TestInnerSignature' { - method ' (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { -- 6 8 -- b 9 -- 10 10 -- 13 11 -+ 4 6 -+ 5 6 -+ 6 6 -+ 7 6 -+ 8 6 -+ 9 7 -+ a 7 -+ b 7 -+ c 7 -+ d 7 -+ e 8 -+ f 8 -+ 10 8 -+ 11 8 -+ 12 8 -+ 13 9 - } - } - - class 'TestInnerSignature$Inner' { - method ' (LTestInnerSignature;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { -+ 9 17 -+ a 17 - b 17 -+ c 17 -+ d 17 -+ e 18 -+ f 18 - 10 18 -+ 11 18 -+ 12 18 -+ 13 19 -+ 14 19 -+ 15 19 - 16 19 -+ 17 19 -+ 18 19 - 19 20 - } - } - - class 'TestInnerSignature$InnerStatic' { - method ' (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { -+ 4 29 -+ 5 29 - 6 29 -+ 7 29 -+ 8 29 -+ 9 30 -+ a 30 - b 30 -+ c 30 -+ d 30 -+ e 31 -+ f 31 - 10 31 -+ 11 31 -+ 12 31 - 13 32 - } - } -diff --git a/testData/results/TestJava9StringConcat.dec b/testData/results/TestJava9StringConcat.dec -index 389bb85905dd216819edf881e0f7fd187a703d64..29890ed8d641519f957d34981fc41e678a7caf2f 100644 ---- a/testData/results/TestJava9StringConcat.dec -+++ b/testData/results/TestJava9StringConcat.dec -@@ -12,12 +12,25 @@ public class TestJava9StringConcat { - - class 'java9/TestJava9StringConcat' { - method 'test1 (Ljava/lang/String;I)Ljava/lang/String;' { -+ 0 4 -+ 1 4 - 2 4 -+ 3 4 -+ 4 4 -+ 5 4 -+ 6 4 - 7 4 - } - - method 'test2 (Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;' { -+ 0 8 -+ 1 8 -+ 2 8 - 3 8 -+ 4 8 -+ 5 8 -+ 6 8 -+ 7 8 - 8 8 - } - } -diff --git a/testData/results/TestKotlinConstructorKt.dec b/testData/results/TestKotlinConstructorKt.dec -index d1e3f7b3570c456d37db7afb8bb2c9ae8096c9d6..0e941450d0dabcbec609f869f674d9cc5bdace33 100644 ---- a/testData/results/TestKotlinConstructorKt.dec -+++ b/testData/results/TestKotlinConstructorKt.dec -@@ -16,12 +16,12 @@ import kotlin.collections.CollectionsKt; - public final class TestKotlinConstructorKt { - private static final List foo(Collection list) { - Iterable $receiver$iv = (Iterable)list;// 2 -- Collection destination$iv$iv = (Collection)(new ArrayList(CollectionsKt.collectionSizeOrDefault($receiver$iv, 10)));// 10 -- Iterator var4 = $receiver$iv.iterator();// 11 -+ Collection destination$iv$iv = (Collection)(new ArrayList(CollectionsKt.collectionSizeOrDefault($receiver$iv, 10))); -+ Iterator var4 = $receiver$iv.iterator();// 10 11 - - while(var4.hasNext()) { - Object item$iv$iv = var4.next(); -- String it = (String)item$iv$iv;// 12 -+ String it = (String)item$iv$iv; - Mapping var10000 = new Mapping; - if (it == null) {// 3 - throw new TypeCastException("null cannot be cast to non-null type kotlin.String"); -@@ -29,7 +29,7 @@ public final class TestKotlinConstructorKt { - - var10000.((String)it); - Mapping var11 = var10000; -- destination$iv$iv.add(var11); -+ destination$iv$iv.add(var11);// 12 - } - - return CollectionsKt.toList((Iterable)((List)destination$iv$iv));// 4 13 -@@ -38,29 +38,84 @@ public final class TestKotlinConstructorKt { - - class 'TestKotlinConstructorKt' { - method 'foo (Ljava/util/Collection;)Ljava/util/List;' { -+ 0 17 - 1 17 -+ 2 17 -+ 3 17 - 4 17 -+ 6 19 -+ c 18 - d 18 -+ e 18 - f 18 -+ 10 18 -+ 11 18 - 15 18 -+ 16 18 -+ 17 18 - 18 18 - 1b 19 -+ 1c 19 -+ 1d 19 -+ 1e 19 -+ 1f 19 - 20 19 -+ 21 19 -+ 22 21 -+ 23 21 - 24 21 -+ 25 21 -+ 26 21 -+ 27 21 -+ 28 21 -+ 2c 22 -+ 2d 22 - 2e 22 -+ 2f 22 -+ 30 22 -+ 31 22 -+ 32 22 - 33 22 -+ 34 22 -+ 35 31 -+ 36 23 -+ 37 23 - 38 23 -+ 39 23 -+ 3a 23 - 3b 23 -+ 3c 23 -+ 43 25 -+ 44 25 - 46 25 - 4d 26 -+ 4e 26 - 52 26 - 53 29 -+ 54 29 -+ 55 29 - 56 29 -+ 57 29 -+ 58 29 - 59 30 -+ 5a 30 -+ 5d 31 -+ 5e 31 - 5f 31 -+ 60 31 -+ 61 31 -+ 62 31 -+ 63 31 -+ 68 34 - 69 34 -+ 6a 34 -+ 6b 34 - 6c 34 -+ 6d 34 -+ 6e 34 - 6f 34 -+ 70 34 -+ 71 34 - 72 34 - } - } -@@ -69,7 +124,7 @@ Lines mapping: - 2 <-> 18 - 3 <-> 26 - 4 <-> 35 --10 <-> 19 -+10 <-> 20 - 11 <-> 20 --12 <-> 24 -+12 <-> 32 - 13 <-> 35 -diff --git a/testData/results/TestLocalsNames.dec b/testData/results/TestLocalsNames.dec -index fe6fe796965768533ba3cde2a2a79ddc37ee7b3e..59563ddeb1c2cb82405b31d9f0073a1df450c9e8 100644 ---- a/testData/results/TestLocalsNames.dec -+++ b/testData/results/TestLocalsNames.dec -@@ -26,40 +26,104 @@ public class TestLocalsNames { - - class 'pkg/TestLocalsNames' { - method 'rename (Ljava/io/File;Z)V' { -+ 0 6 - 1 6 -+ 2 6 -+ 3 6 - 4 6 - 7 7 -+ 8 7 -+ 9 7 - a 7 -+ b 8 - c 8 -+ d 8 -+ e 8 - f 8 -+ 10 8 -+ 11 9 -+ 12 9 - 13 9 -+ 14 9 - 17 10 - 18 10 -+ 19 10 - 1a 12 - 1b 12 -+ 1c 12 -+ 1d 12 -+ 1e 12 -+ 1f 12 -+ 20 12 - 21 12 -+ 24 13 -+ 25 13 -+ 26 13 -+ 27 13 - 28 13 - 29 13 -+ 2a 13 -+ 36 14 -+ 37 14 - 38 14 -+ 39 14 -+ 3a 14 - 3e 14 -+ 3f 14 - 43 14 -+ 44 14 -+ 45 14 - 49 14 -+ 4a 14 -+ 51 16 -+ 52 16 -+ 53 16 -+ 54 16 - 55 16 -+ 56 16 -+ 57 16 - 66 16 -+ 67 16 -+ 6b 16 -+ 6c 16 - 70 16 -+ 71 16 -+ 75 16 -+ 76 16 - 7a 16 -+ 7b 16 -+ 7c 16 - 81 12 -+ 82 12 -+ 83 12 - 87 19 -+ 88 19 -+ 89 19 -+ 8a 19 - 8b 19 - 8c 19 -+ 8d 19 - 8e 20 -+ 8f 20 -+ 90 20 - 98 20 -+ 99 20 -+ 9d 20 -+ 9e 20 - a2 20 -+ a3 20 -+ a7 20 -+ a8 20 -+ a9 20 -+ aa 20 - ab 20 - ac 20 - ad 20 - b1 20 -+ b2 20 - b6 20 -+ b7 20 -+ b8 20 - b9 20 - bc 23 - } -diff --git a/testData/results/TestLocalsSignature.dec b/testData/results/TestLocalsSignature.dec -index 2948bfdb98eaac6f172a7abf518ef795304bc56a..3da716bb86c538148347d67c29354a66dc416c17 100644 ---- a/testData/results/TestLocalsSignature.dec -+++ b/testData/results/TestLocalsSignature.dec -@@ -13,8 +13,14 @@ public class TestLocalsSignature { - class 'pkg/TestLocalsSignature' { - method 'main ([Ljava/lang/String;)V' { - 7 7 -+ 8 8 - 9 8 -+ a 8 - b 8 -+ c 8 -+ d 8 -+ e 8 -+ f 8 - 11 9 - } - } -diff --git a/testData/results/TestMemberAnnotations.dec b/testData/results/TestMemberAnnotations.dec -index 1e3a41c0f8acf669d79049228dc72f63fc387528..72d29afee0f95f9b75898720f39cb0519a48863f 100644 ---- a/testData/results/TestMemberAnnotations.dec -+++ b/testData/results/TestMemberAnnotations.dec -@@ -22,9 +22,14 @@ class TestMemberAnnotations { - - class 'pkg/TestMemberAnnotations' { - method 'f (I)I' { -+ 0 13 -+ 1 13 - 2 13 -+ 3 13 -+ 4 13 - 5 13 - 6 13 -+ 7 13 - 8 13 - 9 13 - } -diff --git a/testData/results/TestMethodReferenceSameName.dec b/testData/results/TestMethodReferenceSameName.dec -index 0dfbeebf93f70504be97a4d5c5487f7b631d5b61..22e9d9213fbd9f82adfe184c960591209f633155 100644 ---- a/testData/results/TestMethodReferenceSameName.dec -+++ b/testData/results/TestMethodReferenceSameName.dec -@@ -14,9 +14,19 @@ public class TestMethodReferenceSameName { - - class 'TestMethodReferenceSameName' { - method 'foo ()V' { -+ 0 4 - 1 4 -- e 5 -- 13 6 -+ 2 4 -+ 3 4 -+ 5 5 -+ 6 5 -+ 7 5 -+ e 6 -+ f 6 -+ 10 6 -+ 11 6 -+ 12 6 -+ 13 7 - } - } - -diff --git a/testData/results/TestPrimitives.dec b/testData/results/TestPrimitives.dec -index 701f2bb3c5f0ba5c2bc18d2f3ee89bc7e901eced..dcbf031b69cc65b108a2cba8f894d02027372032 100644 ---- a/testData/results/TestPrimitives.dec -+++ b/testData/results/TestPrimitives.dec -@@ -172,143 +172,178 @@ public class TestPrimitives { - - class 'pkg/TestPrimitives' { - method 'printAll ()V' { -- 1 6 -- 2 6 -- 6 7 -- 8 7 -- c 8 -- f 8 -- 13 9 -- 15 9 -- 19 10 -- 1c 10 -- 20 11 -- 22 11 -- 26 12 -- 29 12 -- 2d 13 -- 2f 13 -- 33 14 -- 37 14 -- 3b 15 -- 40 15 -- 44 16 -- 4a 16 -- 4e 17 -- 52 17 -- 56 18 -- 5b 18 -- 5f 19 -- 65 19 -- 69 20 -- 6e 20 -- 72 21 -- 78 21 -- 7c 22 -- 81 22 -- 85 23 -- 87 23 -- 8a 23 -- 8d 23 -- 91 24 -- 93 24 -- 96 24 -- 99 24 -- 9d 25 -- 9f 25 -- a2 25 -- a5 25 -- a9 26 -- ab 26 -- ae 26 -- b1 26 -- b5 27 -- b7 27 -- ba 27 -- bd 27 -- c1 28 -- c3 28 -- c6 28 -- c9 28 -- cd 29 -- cf 29 -- d2 29 -- d5 29 -- dd 30 -- e2 30 -- e5 30 -- ea 31 -- ed 31 -- f0 31 -- f5 32 -- f8 32 -- fb 32 -- fe 33 -- 101 33 -- 10a 33 -- 10b 33 -- 111 33 -- 112 33 -- 118 33 -- 11b 33 -- 121 33 -- 123 33 -- 129 33 -- 12b 33 -- 131 33 -- 134 33 -- 138 33 -- 13c 34 -- 13f 34 -- 148 34 -- 14b 34 -- 152 34 -- 155 34 -- 15c 34 -- 15f 34 -- 166 34 -- 169 34 -- 16d 34 -- 175 35 -- 176 35 -- 178 35 -- 17b 35 -- 17d 35 -- 180 35 -- 182 35 -- 185 35 -- 18f 36 -- 194 36 -- 19a 36 -- 19f 36 -- 1a5 36 -- 1aa 36 -- 1b0 36 -- 1b5 36 -- 1c1 37 -- 1c3 37 -- 1c6 37 -- 1c9 37 -- 1cb 37 -- 1ce 37 -- 1d1 37 -- 1d3 37 -- 1d6 37 -- 1d9 37 -- 1db 37 -- 1de 37 -- 1e1 37 -- 1e3 37 -- 1e6 37 -- 1e9 37 -- 1eb 37 -- 1ee 37 -- 1f1 37 -- 1f3 37 -- 1f6 37 -- 1fd 37 -- 202 37 -- 209 38 -+ 0 4 -+ 1 4 -+ 2 4 -+ 3 4 -+ 4 4 -+ 5 5 -+ 6 5 -+ 7 5 -+ 8 5 -+ 9 5 -+ a 5 -+ b 6 -+ c 6 -+ d 6 -+ e 6 -+ f 6 -+ 10 6 -+ 11 6 -+ 12 7 -+ 13 7 -+ 14 7 -+ 15 7 -+ 16 7 -+ 17 7 -+ 18 8 -+ 19 8 -+ 1a 8 -+ 1b 8 -+ 1c 8 -+ 1d 8 -+ 1e 8 -+ 1f 9 -+ 20 9 -+ 21 9 -+ 22 9 -+ 23 9 -+ 24 9 -+ 25 10 -+ 26 10 -+ 27 10 -+ 28 10 -+ 29 10 -+ 2a 10 -+ 2b 10 -+ 2c 11 -+ 2d 11 -+ 2e 11 -+ 2f 11 -+ 30 11 -+ 31 11 -+ 32 12 -+ 33 12 -+ 37 12 -+ 3b 13 -+ 40 13 -+ 44 14 -+ 4a 14 -+ 4e 15 -+ 52 15 -+ 56 16 -+ 5b 16 -+ 5f 17 -+ 65 17 -+ 69 18 -+ 6e 18 -+ 72 19 -+ 78 19 -+ 7c 20 -+ 81 20 -+ 85 21 -+ 87 21 -+ 8a 21 -+ 8d 21 -+ 91 22 -+ 93 22 -+ 96 22 -+ 99 22 -+ 9d 23 -+ 9f 23 -+ a2 23 -+ a5 23 -+ a9 24 -+ ab 24 -+ ae 24 -+ b1 24 -+ b5 25 -+ b7 25 -+ ba 25 -+ bd 25 -+ c1 26 -+ c3 26 -+ c6 26 -+ c9 26 -+ cd 27 -+ cf 27 -+ d2 27 -+ d5 27 -+ dd 28 -+ e2 28 -+ e5 28 -+ ea 29 -+ ed 29 -+ f0 29 -+ f5 30 -+ f8 30 -+ fb 30 -+ fe 31 -+ 101 31 -+ 10a 31 -+ 10b 31 -+ 111 31 -+ 112 31 -+ 118 31 -+ 11b 31 -+ 121 31 -+ 123 31 -+ 129 31 -+ 12b 31 -+ 131 31 -+ 134 31 -+ 138 31 -+ 13c 32 -+ 13f 32 -+ 148 32 -+ 14b 32 -+ 152 32 -+ 155 32 -+ 15c 32 -+ 15f 32 -+ 166 32 -+ 169 32 -+ 16d 32 -+ 175 33 -+ 176 33 -+ 178 33 -+ 17b 33 -+ 17d 33 -+ 180 33 -+ 182 33 -+ 185 33 -+ 18f 34 -+ 194 34 -+ 19a 34 -+ 19f 34 -+ 1a5 34 -+ 1aa 34 -+ 1b0 34 -+ 1b5 34 -+ 1c1 35 -+ 1c3 35 -+ 1c6 35 -+ 1c9 35 -+ 1cb 35 -+ 1ce 35 -+ 1d1 35 -+ 1d3 35 -+ 1d6 35 -+ 1d9 35 -+ 1db 35 -+ 1de 35 -+ 1e1 35 -+ 1e3 35 -+ 1e6 35 -+ 1e9 35 -+ 1eb 35 -+ 1ee 35 -+ 1f1 35 -+ 1f3 35 -+ 1f6 35 -+ 1fd 35 -+ 202 35 -+ 209 36 - } - - method ' (ZBSIJFDC)V' { -diff --git a/testData/results/TestStaticNameClash.dec b/testData/results/TestStaticNameClash.dec -index 1c0f21a81b83a0ca7e8a43ba1d86f7f0f6fe7b8d..f36d336afcae4bd24201a7e0818d10362d098c90 100644 ---- a/testData/results/TestStaticNameClash.dec -+++ b/testData/results/TestStaticNameClash.dec -@@ -10,7 +10,10 @@ public class TestStaticNameClash { - - class 'pkg/TestStaticNameClash' { - method 'setProperty (Ljava/lang/String;)V' { -+ 0 6 - 1 6 -+ 2 6 -+ 3 6 - 4 7 - } - } -diff --git a/testData/results/TestStringConcat.dec b/testData/results/TestStringConcat.dec -index b3fc99579d32896fffb309beba1d89a9f14b84ce..951a761c030b7d6e62e309019b361722ebdd40d9 100644 ---- a/testData/results/TestStringConcat.dec -+++ b/testData/results/TestStringConcat.dec -@@ -12,16 +12,29 @@ public class TestStringConcat { - - class 'pkg/TestStringConcat' { - method 'test1 (Ljava/lang/String;I)Ljava/lang/String;' { -+ 7 4 -+ b 4 - f 4 -+ 10 4 -+ 11 4 - 12 4 - } - - method 'test2 (Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;' { - 7 8 -+ 8 8 -+ c 8 - 10 8 -+ 11 8 -+ 15 8 - 19 8 -+ 1a 8 -+ 1e 8 - 22 8 -+ 23 8 - 27 8 -+ 28 8 -+ 29 8 - 2a 8 - } - } -diff --git a/testData/results/TestStringLiterals.dec b/testData/results/TestStringLiterals.dec -index c5afe1865540afe457073567009b4b96132d0a07..644701c21beb2a80ed07fc6ed7b2873f13d4e2db 100644 ---- a/testData/results/TestStringLiterals.dec -+++ b/testData/results/TestStringLiterals.dec -@@ -12,20 +12,39 @@ public class TestStringLiterals { - class 'pkg/TestStringLiterals' { - method 'main ([Ljava/lang/String;)V' { - 0 4 -+ 1 4 - 2 4 - 9 5 -+ a 5 - e 5 -+ f 5 - 13 5 -+ 14 5 - 18 5 -+ 19 5 - 1d 5 -+ 1e 5 - 22 5 -+ 23 5 - 28 5 -+ 29 5 - 2e 5 -+ 2f 5 - 31 5 - 32 6 -+ 33 6 -+ 34 6 -+ 35 6 - 36 6 -+ 37 6 -+ 38 6 - 39 7 -+ 3a 7 -+ 3b 7 -+ 3c 7 - 3d 7 -+ 3e 7 -+ 3f 7 - 40 8 - } - } -diff --git a/testData/results/TestSwitchOnEnum.dec b/testData/results/TestSwitchOnEnum.dec -index 6e1f77fa247005cb8bb012a91aff96ed78103204..43c9a50f4312736e64116221bfe9140270a81929 100644 ---- a/testData/results/TestSwitchOnEnum.dec -+++ b/testData/results/TestSwitchOnEnum.dec -@@ -50,6 +50,7 @@ public class TestSwitchOnEnum { - - class 'pkg/TestSwitchOnEnum' { - method 'testSOE (Ljava/util/concurrent/TimeUnit;)I' { -+ 3 8 - 8 8 - 24 10 - 25 10 -diff --git a/testData/results/TestSynchronizedMapping.dec b/testData/results/TestSynchronizedMapping.dec -index 84ad48a1e66013579286702e7fee9e562a8369e8..6778aa19b6d347f20cac678bd6414c2e1eac369d 100644 ---- a/testData/results/TestSynchronizedMapping.dec -+++ b/testData/results/TestSynchronizedMapping.dec -@@ -16,16 +16,26 @@ public class TestSynchronizedMapping { - - class 'pkg/TestSynchronizedMapping' { - method 'test (I)I' { -+ 0 4 - 3 4 - 4 5 -+ 5 5 -+ 6 5 - 8 6 - 12 8 -+ 13 8 -+ 14 8 - 15 8 - } - - method 'test2 (Ljava/lang/String;)V' { - 0 12 -+ 1 12 -+ 2 12 -+ 3 12 - 4 12 -+ 5 12 -+ 6 12 - 7 13 - } - } -diff --git a/testData/results/TestSyntheticAccess.dec b/testData/results/TestSyntheticAccess.dec -index d5016a28f9ecd2cd30317c4c595b8c30b21b63ea..290e7a3cd313d5b54036e0ce2b5eaed572524cb6 100644 ---- a/testData/results/TestSyntheticAccess.dec -+++ b/testData/results/TestSyntheticAccess.dec -@@ -39,43 +39,66 @@ class TestSyntheticAccess { - - class 'pkg/TestSyntheticAccess$Assigner' { - method 'assignI (I)V' { -+ 1 8 -+ 2 8 -+ 3 8 -+ 4 8 - 5 8 - 9 9 - } - - method 'assignS (I)V' { -- 1 12 -+ 0 12 -+ 2 12 -+ 3 12 -+ 4 12 - 5 13 - } - } - - class 'pkg/TestSyntheticAccess$Incrementer' { - method 'orI ()V' { -- 8 18 -+ 1 18 -+ 2 18 -+ 3 18 -+ 4 18 -+ 5 18 -+ 6 18 -+ 7 18 - b 18 - d 18 - 11 19 - } - - method 'incrementI ()V' { -+ 1 22 - 2 22 -+ 3 22 - 4 22 -+ 7 22 - 8 23 - } - - method 'decrementI ()V' { -+ 1 26 - 2 26 -+ 3 26 - 4 26 -+ 6 26 - 8 27 - } - - method 'incrementS ()V' { - 0 30 -- 4 31 -+ 1 30 -+ 2 30 -+ 4 30 - } - - method 'decrementS ()V' { - 0 34 -+ 1 34 -+ 2 34 - 4 35 - } - } -diff --git a/testData/results/TestThrowException.dec b/testData/results/TestThrowException.dec -index 7c52234203a98704f4631c8e7d3b6edd27f18c4f..1344ac4d312e381ad98e3c1ef2a33a36d6f6952e 100644 ---- a/testData/results/TestThrowException.dec -+++ b/testData/results/TestThrowException.dec -@@ -26,10 +26,15 @@ class 'pkg/TestThrowException$1' { - - class 'pkg/TestThrowException' { - method ' (I)V' { -+ 4 6 - 5 6 - c 7 -+ d 7 - 11 7 -+ 12 9 - 1b 9 -+ 1c 9 -+ 1d 9 - 1e 15 - } - } -diff --git a/testData/results/TestTryCatchFinally.dec b/testData/results/TestTryCatchFinally.dec -index 2af717c0764a39b168d490d00d0933185ad11fde..20e9afb72b2d2dabc76d29f6bb1f4ef2bfbc5a20 100644 ---- a/testData/results/TestTryCatchFinally.dec -+++ b/testData/results/TestTryCatchFinally.dec -@@ -42,42 +42,74 @@ public class TestTryCatchFinally { - class 'pkg/TestTryCatchFinally' { - method 'test1 (Ljava/lang/String;)V' { - 0 5 -+ 1 5 -+ 2 5 - 3 5 -+ 4 5 - 5 5 - 14 8 -+ 15 8 -+ 16 8 - 17 8 -+ 18 8 - 19 8 - 1f 9 -- 2b 12 -- 2d 12 -- 30 12 -- 38 15 -+ 2b 13 -+ 2c 13 -+ 2d 13 -+ 2e 13 -+ 2f 13 -+ 30 13 -+ 31 13 -+ 38 16 - } - - method 'foo (I)I' { -- 1 18 -- 2 18 -- c 19 -- e 20 -- f 20 -- 13 21 -- 1b 23 -+ 0 19 -+ 1 19 -+ 2 19 -+ c 20 -+ d 21 -+ e 21 -+ f 21 -+ 12 22 -+ 13 22 -+ 1b 24 - } - - method 'test (Ljava/lang/String;)I' { -- 1 29 -- 4 29 -- e 30 -- f 31 -- 10 32 -- 1a 32 -- 23 32 -- 26 32 -- 31 37 -- 34 34 -- 35 34 -- 38 34 -- 3f 37 -+ 0 30 -+ 1 30 -+ 2 30 -+ 3 30 -+ 4 30 -+ d 31 -+ e 31 -+ f 32 -+ 10 33 -+ 11 33 -+ 12 33 -+ 1a 33 -+ 1b 33 -+ 23 33 -+ 24 33 -+ 25 33 -+ 26 33 -+ 31 38 -+ 32 38 -+ 33 38 -+ 34 35 -+ 35 35 -+ 36 35 -+ 37 35 -+ 38 35 -+ 39 35 -+ 3a 38 -+ 3b 38 -+ 3c 38 -+ 3d 38 -+ 3e 38 -+ 3f 38 - } - } - -diff --git a/testData/results/TestVarArgCalls.dec b/testData/results/TestVarArgCalls.dec -index 6cdcd8fc638ceeec823172b2859ee8f970f61327..db4cb49cc7816f05dd2e3d82a6b79a7405001e4d 100644 ---- a/testData/results/TestVarArgCalls.dec -+++ b/testData/results/TestVarArgCalls.dec -@@ -27,58 +27,135 @@ public class TestVarArgCalls { - - class 'pkg/TestVarArgCalls' { - method 'doSmth ()V' { -+ 0 4 - 1 4 -+ 2 4 - 7 4 -+ 8 4 -+ 9 4 -+ a 5 - b 5 -+ c 5 - 13 5 -+ 14 5 - 16 5 -+ 17 5 -+ 18 5 -+ 19 6 - 1a 6 -+ 1b 6 - 22 6 -+ 23 6 - 27 6 -+ 28 6 - 2a 6 -+ 2b 6 -+ 2c 6 -+ 2d 7 - 2e 7 -+ 2f 7 - 34 7 -+ 35 7 -+ 36 7 -+ 37 8 - 38 8 -+ 39 8 - 46 8 -+ 47 8 - 4a 8 -+ 4b 8 -+ 4c 8 -+ 4d 9 - 4e 9 -+ 4f 9 - 5c 9 -+ 5d 9 - 68 9 -+ 69 9 - 6c 9 -+ 6d 9 -+ 6e 9 - 6f 10 -+ 70 10 - 75 10 -+ 76 10 -+ 77 10 - 79 11 -+ 7a 11 - 81 11 -+ 82 11 - 83 11 -+ 84 11 -+ 85 11 - 87 11 -+ 88 11 -+ 89 11 - 8b 12 -+ 8c 12 - 93 12 -+ 94 12 - 95 12 -+ 96 12 -+ 97 12 - 9b 12 -+ 9c 12 - 9e 12 -+ 9f 12 -+ a0 12 - a8 13 -+ a9 13 - ab 13 - ac 14 -+ ad 14 -+ b4 14 - b6 14 -+ b7 14 -+ b8 14 - ba 15 -+ bb 15 -+ bc 15 - bd 15 -+ be 15 -+ bf 15 - c0 15 -+ c1 15 -+ c2 15 - c4 16 - } - - method 'printAll (Ljava/lang/String;[Ljava/lang/String;)V' { - 0 19 -+ 1 19 -+ 2 19 -+ 3 19 -+ 4 19 - 5 19 -+ 6 19 -+ 7 19 - 8 19 -+ 9 19 -+ a 19 - b 19 -+ c 19 -+ d 19 - e 20 - } - - method 'printComplex (Ljava/lang/String;[[Ljava/lang/String;)V' { - 0 23 -+ 1 23 -+ 2 23 -+ 3 23 -+ 4 23 - 5 23 -+ 6 23 -+ 7 23 - 8 23 -+ 9 23 -+ a 23 - b 23 -+ c 23 -+ d 23 - e 24 - } - } diff --git a/FernFlower-Patches/0005-NUll-constructor-synthetic-classes-can-have-content-.patch b/FernFlower-Patches/0005-NUll-constructor-synthetic-classes-can-have-content-.patch new file mode 100644 index 0000000..0bdc67b --- /dev/null +++ b/FernFlower-Patches/0005-NUll-constructor-synthetic-classes-can-have-content-.patch @@ -0,0 +1,27 @@ +From 211a6f999cc0fc746ba73d6a9e4fd91be19a69e8 Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sat, 1 Aug 2015 17:52:35 -0700 +Subject: [PATCH 005/122] NUll constructor synthetic classes can have content + as well so don't rely on it being a stub, just being anonymous. You can't + legitimatly have a anonymous argument. + +--- + .../java/decompiler/modules/decompiler/exps/NewExprent.java | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +index 24facc9..6dad7c9 100644 +--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java ++++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +@@ -327,7 +327,7 @@ public class NewExprent extends Exprent { + + if (i == lstParameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL) { + ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(leftType.value); +- if (node != null && node.namelessConstructorStub) { ++ if (node != null && node.type == ClassNode.CLASS_ANONYMOUS) { + break; // skip last parameter of synthetic constructor call + } + } +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0006-Sort-inner-class-lists-to-produce-a-consistant-decom.patch b/FernFlower-Patches/0006-Sort-inner-class-lists-to-produce-a-consistant-decom.patch new file mode 100644 index 0000000..0afb25e --- /dev/null +++ b/FernFlower-Patches/0006-Sort-inner-class-lists-to-produce-a-consistant-decom.patch @@ -0,0 +1,81 @@ +From fdff6cfcb291cf7dcba48ce13e2aefcb7dae0d5b Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sat, 1 Aug 2015 18:40:43 -0700 +Subject: [PATCH 006/122] Sort inner class lists to produce a consistant + decompile. Different JVMs sort HashSets differently causing inner classes to + get shuffled. + +--- + .../jetbrains/java/decompiler/main/ClassesProcessor.java | 9 ++++++++- + .../java/decompiler/main/rels/LambdaProcessor.java | 2 ++ + .../java/decompiler/main/rels/NestedClassProcessor.java | 1 + + 3 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +index 5a56641..b3e9d81 100644 +--- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java ++++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +@@ -228,6 +228,7 @@ public class ClassesProcessor { + stack.add(nestedClass); + } + } ++ Collections.sort(superNode.nested); + } + } + } +@@ -342,7 +343,7 @@ public class ClassesProcessor { + } + + +- public static class ClassNode { ++ public static class ClassNode implements Comparable { + + public static final int CLASS_ROOT = 0; + public static final int CLASS_MEMBER = 1; +@@ -441,5 +442,11 @@ public class ClassesProcessor { + public boolean is_method_reference; + public boolean is_content_method_static; + } ++ ++ @Override ++ public int compareTo(ClassNode o) ++ { ++ return this.classStruct.qualifiedName.compareTo(o.classStruct.qualifiedName); ++ } + } + } +diff --git a/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java +index 0704efd..809af6d 100644 +--- a/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java ++++ b/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java +@@ -119,6 +119,7 @@ public class LambdaProcessor { + } + } + } ++ Collections.sort(node.nested); + } + + mt.releaseResources(); +@@ -133,6 +134,7 @@ public class LambdaProcessor { + + parent_class.nested.add(nd); + nd.parent = parent_class; ++ Collections.sort(parent_class.nested); + } + } + } +diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +index 798010e..9aedf22 100644 +--- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java ++++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +@@ -248,6 +248,7 @@ public class NestedClassProcessor { + if (setEnclosing.contains(node.classStruct.qualifiedName)) { + node.nested.add(child); + child.parent = node; ++ Collections.sort(node.nested); + + return true; + } +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0007-Add-an-LVT-test-so-we-can-quickly-iterate-LVT-hackin.patch b/FernFlower-Patches/0007-Add-an-LVT-test-so-we-can-quickly-iterate-LVT-hackin.patch new file mode 100644 index 0000000..6fa1081 --- /dev/null +++ b/FernFlower-Patches/0007-Add-an-LVT-test-so-we-can-quickly-iterate-LVT-hackin.patch @@ -0,0 +1,153 @@ +From 213752acb3080ed6bff297f5a4e54b09998cf10a Mon Sep 17 00:00:00 2001 +From: cpw +Date: Sun, 2 Aug 2015 10:43:54 -0400 +Subject: [PATCH 007/122] Add an LVT test so we can quickly iterate LVT hacking + +--- + .../jetbrains/java/decompiler/LVTTest.java | 33 ++++++++++++++++++ + testData/classes/pkg/TestLVT.class | Bin 0 -> 1672 bytes + testData/results/TestLVT.dec | 29 +++++++++++++++ + testData/src/pkg/TestLVT.java | 27 ++++++++++++++ + 4 files changed, 89 insertions(+) + create mode 100644 test/org/jetbrains/java/decompiler/LVTTest.java + create mode 100644 testData/classes/pkg/TestLVT.class + create mode 100644 testData/results/TestLVT.dec + create mode 100644 testData/src/pkg/TestLVT.java + +diff --git a/test/org/jetbrains/java/decompiler/LVTTest.java b/test/org/jetbrains/java/decompiler/LVTTest.java +new file mode 100644 +index 0000000..2d39827 +--- /dev/null ++++ b/test/org/jetbrains/java/decompiler/LVTTest.java +@@ -0,0 +1,33 @@ ++/* ++ * Copyright 2000-2014 JetBrains s.r.o. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.jetbrains.java.decompiler; ++ ++import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; ++import org.junit.Test; ++ ++import java.util.HashMap; ++import java.util.Map; ++ ++public class LVTTest extends SingleClassesTestBase { ++ @Override ++ protected Map getDecompilerOptions() { ++ return new HashMap() {{ ++ put(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS, "1"); ++ }}; ++ } ++ ++ @Test public void testMatch1() { doTest("pkg/TestLVT"); } ++} +diff --git a/testData/classes/pkg/TestLVT.class b/testData/classes/pkg/TestLVT.class +new file mode 100644 +index 0000000000000000000000000000000000000000..d8a5829d4f6504567ecf46bf65167047e41cd291 +GIT binary patch +literal 1672 +zcmZ`(T~k|C6kR9WCsQID{))ny*Q2I>Woq +zJUPDjqT^Vf^&vRc=@0N1_+OkUu9KS#fglskJs)eYz4ktPpTA%J`2s)=U+D-54A-CR +zWw+d>?-aLmXadm#`BY}hvbvYu*g0@ZzCdKot9t&tz)(6<6wsDxyRL;Hm^Q+Q2wZZ! +zs=MB*?6{3Bxl?upVot3j%SGAn)VjN=`TJf|V8rQjSs;7G_4jML0=Lr6sqam{;Z^qv +zgFBg`fl*pDOSQT?V_-}`59ZQ9qIZxpFy1@JNgXMHu?~65_sZFYMnfJtUemX58K#bF +z0^{dhFSfk$uG_G112=WNdL}V}I2*6wbvk(}%Pn`~8-dCG0D|NdGJ_FVxQYptx;F(9 +z{U+U*Gew2CWh0FYILHIL1zUM_b{vD{@FAhHhs5Z<6S&pZPi*VwL}n*SIa);{rlu}Wre{M +z@Scvj-X)$rwlS|#sn?Z7xoY5j>gkk3?hXrNQNZl2SP35pjGk7)BiY +zg{W24N2kIliigRweRNpw_0mKiR1wYfN$6hOJnirG!N_<4>SDW*O<$It(4yPA)@H5M +zD7nj?YHqvxT-;S^*#o@0PC7!I@jc+EbDiZ^@Eg8;4C6OWLa;chW5B>LM>_!UJHnNT +zS8$0tG#39r>!6>-qHD3(`p|vtS1iTi`EV?mk37fa?PFZY>(6m@d+HBdKgJuWa2u1U +z2#18$#_g2e#&jER<&EF*PReK_|E(qxTGaaKxg23 +z=PTUZ#2B`@`!y1fNa6tFIO1FMJ@h!Xa_vQ$8h*nvo+3CvVSIv!+b{YBk_)U +ziLr`xY*0lM56J28BI0bhan2(2JcY;jgqdAn=0D}0fg;iC)S*#BU=g8`z(S`UWwAxv +zQP;x6XVj3S*MO}^wgB}x5nu3Z0@_R1I&SbM9-c7DaIgqQ4fq#})W1z^2w(mOPXBh_ + +literal 0 +HcmV?d00001 + +diff --git a/testData/results/TestLVT.dec b/testData/results/TestLVT.dec +new file mode 100644 +index 0000000..b1b7e2e +--- /dev/null ++++ b/testData/results/TestLVT.dec +@@ -0,0 +1,29 @@ ++package pkg; ++ ++import java.util.ArrayList; ++import java.util.HashMap; ++ ++public class TestLVT { ++ ++ ++ public static void method(String a1, String a2) { ++ String scope1 = "scope1"; ++ String scope1a = "scope1a"; ++ for(int i = 0; i < 10; ++i) { ++ String scope2 = "scope2"; ++ String scope2a = "scope2a"; ++ ArrayList noise = new ArrayList(); ++ String spam = scope1 + scope2 + scope2a + i + noise; ++ System.out.println(spam); ++ } ++ for (long i = 0L; i < 10L; ++i) { ++ String scope2 = "scope2+1"; ++ String scope2a = "scope2+1a"; ++ HashMap noise = new HashMap(); ++ String spam = scope1a + scope2 + scope2a + i + noise; ++ System.out.println(spam); ++ } ++ ++ } ++} ++ +diff --git a/testData/src/pkg/TestLVT.java b/testData/src/pkg/TestLVT.java +new file mode 100644 +index 0000000..05b5228 +--- /dev/null ++++ b/testData/src/pkg/TestLVT.java +@@ -0,0 +1,27 @@ ++package pkg; ++ ++import java.util.ArrayList; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++public class TestLVT { ++ public static void method(String a1, String a2) { ++ String scope1 = "scope1"; ++ String scope1a = "scope1a"; ++ for (int i=0; i<10; i++) { ++ String scope2 = "scope2"; ++ String scope2a = "scope2a"; ++ List noise = new ArrayList(); ++ String spam = scope1 + scope2 + scope2a + i + noise; ++ System.out.println(spam); ++ } ++ for (long i=0; i<10; i++) { ++ String scope2 = "scope2+1"; ++ String scope2a = "scope2+1a"; ++ Map noise = new HashMap(); ++ String spam = scope1a + scope2 + scope2a + i + noise; ++ System.out.println(spam); ++ } ++ } ++} +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0007-Reintroduce-DotExporter-for-debugging-purposes.patch b/FernFlower-Patches/0007-Reintroduce-DotExporter-for-debugging-purposes.patch deleted file mode 100644 index 0d3d6de..0000000 --- a/FernFlower-Patches/0007-Reintroduce-DotExporter-for-debugging-purposes.patch +++ /dev/null @@ -1,393 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Wed, 12 Apr 2017 18:37:18 -0700 -Subject: [PATCH] Reintroduce DotExporter for debugging purposes - - -diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 327a6e64f06d7ef60dc1bb3139aab490a2f7c2df..7d41769adee0974a02e0ef5a0518f9f9e53c8b58 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -@@ -24,6 +24,7 @@ import org.jetbrains.java.decompiler.struct.attr.StructEnclosingMethodAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.util.DotExporter; - import org.jetbrains.java.decompiler.util.InterpreterUtil; - - import java.util.*; -@@ -261,6 +262,7 @@ public class NestedClassProcessor { - // iterate enclosing class - for (MethodWrapper method : node.getWrapper().getMethods()) { - if (method.root != null) { // neither abstract, nor native -+ DotExporter.toDotFile(method.getOrBuildGraph(), method.methodStruct, "computeLocalVars"); - method.getOrBuildGraph().iterateExprents(exprent -> { - List lst = exprent.getAllExprents(true); - lst.add(exprent); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java -index 70b053d4138127c772f72eca7a54a1b8b3098cbf..82e8870671180ade3be93bbb54920b0321a9912b 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java -@@ -15,6 +15,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement.Statemen - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; - import org.jetbrains.java.decompiler.struct.StructMethod; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; -+import org.jetbrains.java.decompiler.util.DotExporter; - import org.jetbrains.java.decompiler.util.FastSparseSetFactory; - import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet; - import org.jetbrains.java.decompiler.util.SFormsFastMapDirect; -@@ -54,9 +55,7 @@ public class SSAConstructorSparseEx { - FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); - DirectGraph dgraph = flatthelper.buildDirectGraph(root); - -- // try { -- // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot")); -- // } catch(Exception ex) {ex.printStackTrace();} -+ DotExporter.toDotFile(dgraph, mt, "ssaSplitVariables"); - - List setInit = new ArrayList<>(); - for (int i = 0; i < 64; i++) { -@@ -69,20 +68,19 @@ public class SSAConstructorSparseEx { - - setCatchMaps(root, dgraph, flatthelper); - -+ int itteration = 1; - HashSet updated = new HashSet<>(); - do { - // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava()); -- ssaStatements(dgraph, updated); -+ ssaStatements(dgraph, updated, mt, itteration++); - // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava()); - } - while (!updated.isEmpty()); - } - -- private void ssaStatements(DirectGraph dgraph, HashSet updated) { -+ private void ssaStatements(DirectGraph dgraph, HashSet updated, StructMethod mt, int itteration) { - -- // try { -- // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot")); -- // } catch(Exception ex) {ex.printStackTrace();} -+ DotExporter.toDotFile(dgraph, mt, "ssaStatements_" + itteration, outVarVersions); - - for (DirectNode node : dgraph.nodes) { - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java -index 8cd9f1de252412494f36a847167a9b74a7dd7625..5e1e323a6e2043d776c513e800056be200ab2971 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java -@@ -12,6 +12,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionsGraph; - import org.jetbrains.java.decompiler.struct.StructMethod; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; -+import org.jetbrains.java.decompiler.util.DotExporter; - import org.jetbrains.java.decompiler.util.FastSparseSetFactory; - import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet; - import org.jetbrains.java.decompiler.util.SFormsFastMapDirect; -@@ -68,6 +69,8 @@ public class SSAUConstructorSparseEx { - FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); - DirectGraph dgraph = flatthelper.buildDirectGraph(root); - -+ DotExporter.toDotFile(dgraph, mt, "ssauSplitVariables"); -+ - List setInit = new ArrayList<>(); - for (int i = 0; i < 64; i++) { - setInit.add(i); -@@ -78,25 +81,24 @@ public class SSAUConstructorSparseEx { - - setCatchMaps(root, dgraph, flatthelper); - -- // try { -- // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot")); -- // } catch(Exception ex) {ex.printStackTrace();} -- -+ int itteration = 1; - HashSet updated = new HashSet<>(); - do { - // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava()); -- ssaStatements(dgraph, updated, false); -+ ssaStatements(dgraph, updated, false, mt, itteration++); - // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava()); - } - while (!updated.isEmpty()); - - -- ssaStatements(dgraph, updated, true); -+ ssaStatements(dgraph, updated, true, mt, itteration++); - - ssuversions.initDominators(); - } - -- private void ssaStatements(DirectGraph dgraph, HashSet updated, boolean calcLiveVars) { -+ private void ssaStatements(DirectGraph dgraph, HashSet updated, boolean calcLiveVars, StructMethod mt, int itteration) { -+ -+ DotExporter.toDotFile(dgraph, mt, "ssauStatements_" + itteration); - - for (DirectNode node : dgraph.nodes) { - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -index 472faf9ad843f4d4bafdc2cf7753b67d8c34bddc..d6a9c2a29c73d778eb383d718094b7548d14d2f3 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -@@ -14,6 +14,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; - import org.jetbrains.java.decompiler.struct.StructMethod; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.util.DotExporter; - import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet; - - import java.util.*; -@@ -36,6 +37,8 @@ public class VarVersionsProcessor { - FlattenStatementsHelper flattenHelper = new FlattenStatementsHelper(); - DirectGraph graph = flattenHelper.buildDirectGraph(root); - -+ DotExporter.toDotFile(graph, method, "setVarVersions"); -+ - mergePhiVersions(ssa, graph); - - typeProcessor.calculateVarTypes(root, graph); -diff --git a/src/org/jetbrains/java/decompiler/util/DotExporter.java b/src/org/jetbrains/java/decompiler/util/DotExporter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f9ce78507cb70255e090088fbf1e1834dfdf902f ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/util/DotExporter.java -@@ -0,0 +1,238 @@ -+package org.jetbrains.java.decompiler.util; -+ -+import java.io.BufferedOutputStream; -+import java.io.File; -+import java.io.FileOutputStream; -+import java.util.Collections; -+import java.util.HashSet; -+import java.util.List; -+import java.util.Map; -+import java.util.Set; -+import java.util.Map.Entry; -+ -+import org.jetbrains.java.decompiler.code.cfg.BasicBlock; -+import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph; -+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; -+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph; -+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionEdge; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionNode; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionsGraph; -+import org.jetbrains.java.decompiler.struct.StructMethod; -+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet; -+ -+public class DotExporter { -+ private static final String DOTS_FOLDER = System.getProperty("DOT_EXPORT_DIR", null); -+ private static final boolean DUMP_DOTS = DOTS_FOLDER != null; -+ // http://graphs.grevian.org/graph is a nice visualizer for the outputed dots. -+ -+ private static String toDotFormat(Statement stat) { -+ -+ StringBuffer buffer = new StringBuffer(); -+ -+ buffer.append("digraph G {\r\n"); -+ -+ for(Statement st : stat.getStats()) { -+ -+ String sourceid = st.id + (st.getSuccessorEdges(StatEdge.EdgeType.EXCEPTION).isEmpty()?"":"000000"); -+ -+ buffer.append(sourceid+" [shape=box,label=\""+sourceid+"\"];\r\n"); -+ -+ for(StatEdge edge : st.getSuccessorEdges(StatEdge.EdgeType.DIRECT_ALL)) { -+ String destid = edge.getDestination().id + (edge.getDestination().getSuccessorEdges(StatEdge.EdgeType.EXCEPTION).isEmpty()?"":"000000"); -+ -+ buffer.append(sourceid+"->"+destid+";\r\n"); -+ -+ if(!stat.getStats().contains(edge.getDestination())) { -+ buffer.append(destid+" [label=\""+destid+"\"];\r\n"); -+ } -+ } -+ -+ for(StatEdge edge : st.getSuccessorEdges(StatEdge.EdgeType.EXCEPTION)) { -+ String destid = edge.getDestination().id + (edge.getDestination().getSuccessorEdges(StatEdge.EdgeType.EXCEPTION).isEmpty()?"":"000000"); -+ -+ buffer.append(sourceid+" -> "+destid+" [style=dotted];\r\n"); -+ -+ if(!stat.getStats().contains(edge.getDestination())) { -+ buffer.append(destid+" [label=\""+destid+"\"];\r\n"); -+ } -+ } -+ } -+ -+ buffer.append("}"); -+ -+ return buffer.toString(); -+ } -+ -+ -+ private static String toDotFormat(ControlFlowGraph graph, boolean showMultipleEdges) { -+ -+ StringBuffer buffer = new StringBuffer(); -+ -+ buffer.append("digraph G {\r\n"); -+ -+ List blocks = graph.getBlocks(); -+ for(int i=0;i suc = block.getSuccessors(); -+ if(!showMultipleEdges) { -+ HashSet set = new HashSet<>(); -+ set.addAll(suc); -+ suc = Collections.list(Collections.enumeration(set)); -+ } -+ for(int j=0;j"+suc.get(j).id+";\r\n"); -+ } -+ -+ -+ suc = block.getSuccessorExceptions(); -+ if(!showMultipleEdges) { -+ HashSet set = new HashSet<>(); -+ set.addAll(suc); -+ suc = Collections.list(Collections.enumeration(set)); -+ } -+ for(int j=0;j "+suc.get(j).id+" [style=dotted];\r\n"); -+ } -+ } -+ -+ buffer.append("}"); -+ -+ return buffer.toString(); -+ } -+ -+ private static String toDotFormat(VarVersionsGraph graph) { -+ -+ StringBuffer buffer = new StringBuffer(); -+ -+ buffer.append("digraph G {\r\n"); -+ -+ List blocks = graph.nodes; -+ for(int i=0;i"+(dest.var*1000+dest.version)+(edge.type==VarVersionEdge.EDGE_PHANTOM?" [style=dotted]":"")+";\r\n"); -+ } -+ } -+ -+ buffer.append("}"); -+ -+ return buffer.toString(); -+ } -+ -+ private static String toDotFormat(DirectGraph graph, Map vars) { -+ -+ StringBuffer buffer = new StringBuffer(); -+ -+ buffer.append("digraph G {\r\n"); -+ -+ List blocks = graph.nodes; -+ for(int i=0;i>> lst = map.entryList(); -+ if (lst != null) { -+ for (Entry> entry : lst) { -+ label.append("\\n").append(entry.getKey()); -+ Set set = entry.getValue().toPlainSet(); -+ label.append("=").append(set.toString()); -+ } -+ } -+ } -+ -+ buffer.append(directBlockIdToDot(block.id)+" [shape=box,label=\""+label+"\"];\r\n"); -+ -+ for(DirectNode dest: block.successors) { -+ buffer.append(directBlockIdToDot(block.id)+"->"+directBlockIdToDot(dest.id)+";\r\n"); -+ } -+ } -+ -+ buffer.append("}"); -+ -+ return buffer.toString(); -+ } -+ -+ private static String directBlockIdToDot(String id) { -+ id = id.replaceAll("_try", "999"); -+ id = id.replaceAll("_tail", "888"); -+ -+ id = id.replaceAll("_init", "111"); -+ id = id.replaceAll("_cond", "222"); -+ id = id.replaceAll("_inc", "333"); -+ return id; -+ } -+ -+ private static File getFile(StructMethod mt, String suffix) { -+ File root = new File(DOTS_FOLDER + mt.getClassQualifiedName()); -+ if (!root.isDirectory()) -+ root.mkdirs(); -+ return new File(root, -+ mt.getName().replace('<', '.').replace('>', '_') + -+ mt.getDescriptor().replace('/', '.') + -+ '_' + suffix + ".dot"); -+ } -+ -+ public static void toDotFile(DirectGraph dgraph, StructMethod mt, String suffix) { -+ toDotFile(dgraph, mt, suffix, null); -+ } -+ public static void toDotFile(DirectGraph dgraph, StructMethod mt, String suffix, Map vars) { -+ if (!DUMP_DOTS) -+ return; -+ try{ -+ BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(getFile(mt, suffix))); -+ out.write(toDotFormat(dgraph, vars).getBytes()); -+ out.close(); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } -+ } -+ -+ public static void toDotFile(Statement stat, StructMethod mt, String suffix) { -+ if (!DUMP_DOTS) -+ return; -+ try{ -+ BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(getFile(mt, suffix))); -+ out.write(toDotFormat(stat).getBytes()); -+ out.close(); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } -+ } -+ -+ public static void toDotFile(VarVersionsGraph graph, StructMethod mt, String suffix) { -+ if (!DUMP_DOTS) -+ return; -+ try{ -+ BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(getFile(mt, suffix))); -+ out.write(toDotFormat(graph).getBytes()); -+ out.close(); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } -+ } -+ -+ public static void toDotFile(ControlFlowGraph graph, StructMethod mt, String suffix, boolean showMultipleEdges) { -+ if (!DUMP_DOTS) -+ return; -+ try{ -+ BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(getFile(mt, suffix))); -+ out.write(toDotFormat(graph, showMultipleEdges).getBytes()); -+ out.close(); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } -+ } -+} -\ No newline at end of file diff --git a/FernFlower-Patches/0008-Capture-the-LVT-and-LVTT-properly-into-some-structur.patch b/FernFlower-Patches/0008-Capture-the-LVT-and-LVTT-properly-into-some-structur.patch new file mode 100644 index 0000000..53068a6 --- /dev/null +++ b/FernFlower-Patches/0008-Capture-the-LVT-and-LVTT-properly-into-some-structur.patch @@ -0,0 +1,172 @@ +From f83b43ba0aaf6e5fb17d17a9fcaa2420ab8aa0ff Mon Sep 17 00:00:00 2001 +From: cpw +Date: Sun, 2 Aug 2015 14:07:52 -0400 +Subject: [PATCH 008/122] Capture the LVT and LVTT properly, into some + structured data. Ends seem to be the way to index the variable table. Next + up, we need to capture the block ends in the var parsing code, so we can then + match up later. + +--- + .../java/decompiler/struct/StructMember.java | 4 +- + .../struct/attr/StructGeneralAttribute.java | 3 +- + .../StructLocalVariableTableAttribute.java | 77 ++++++++++++++++++- + 3 files changed, 79 insertions(+), 5 deletions(-) + +diff --git a/src/org/jetbrains/java/decompiler/struct/StructMember.java b/src/org/jetbrains/java/decompiler/struct/StructMember.java +index f681e19..724c0db 100644 +--- a/src/org/jetbrains/java/decompiler/struct/StructMember.java ++++ b/src/org/jetbrains/java/decompiler/struct/StructMember.java +@@ -57,9 +57,9 @@ public class StructMember { + StructGeneralAttribute attribute = readAttribute(in, pool, name); + + if (attribute != null) { +- if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) && attributes.containsKey(name)) { ++ if ((StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) || StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.equals(name)) && attributes.containsKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE)) { + // merge all variable tables +- StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name); ++ StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE); + table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute); + } + else { +diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java +index dc0ebc6..87f5741 100644 +--- a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java ++++ b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java +@@ -42,6 +42,7 @@ public class StructGeneralAttribute { + public static final String ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations"; + public static final String ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations"; + public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; ++ public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; + public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; + public static final String ATTRIBUTE_BOOTSTRAP_METHODS = "BootstrapMethods"; + public static final String ATTRIBUTE_SYNTHETIC = "Synthetic"; +@@ -85,7 +86,7 @@ public class StructGeneralAttribute { + ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(name)) { + attr = new StructAnnotationTypeAttribute(); + } +- else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name)) { ++ else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) || ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.equals(name)) { + attr = new StructLocalVariableTableAttribute(); + } + else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(name)) { +diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java +index fceae35..04f534e 100644 +--- a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java ++++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java +@@ -19,9 +19,14 @@ import org.jetbrains.java.decompiler.struct.consts.ConstantPool; + import org.jetbrains.java.decompiler.util.DataInputFullStream; + + import java.io.IOException; ++import java.util.ArrayList; + import java.util.Collections; + import java.util.HashMap; ++import java.util.HashSet; ++import java.util.List; + import java.util.Map; ++import java.util.Map.Entry; ++import java.util.Set; + + /* + u2 local_variable_table_length; +@@ -35,21 +40,80 @@ import java.util.Map; + */ + public class StructLocalVariableTableAttribute extends StructGeneralAttribute { + ++ public static class LVTVariable implements Comparable { ++ public final String name; ++ public final int start; ++ public final int end; ++ public final int index; ++ private String desc; ++ private String sig; ++ private boolean isLVTT; ++ LVTVariable(String name, String desc, int start, int end, int index, boolean isLVTT) { ++ this.name = name; ++ this.desc = desc; ++ this.start = start; ++ this.end = end; ++ this.index = index; ++ this.isLVTT = isLVTT; ++ } ++ ++ void merge(LVTVariable other) { ++ if (other.isLVTT && this.sig == null) { ++ this.sig = other.desc; ++ } ++ } ++ @Override ++ public boolean equals(Object obj) { ++ return ((LVTVariable) obj).index == index && ((LVTVariable) obj).end == end; ++ } ++ @Override ++ public int hashCode() { ++ return index * 31 + end; ++ } ++ ++ public void addTo(Map> endpoints) { ++ Set ends = endpoints.get(this.end); ++ if (ends == null) { ++ ends = new HashSet(); ++ endpoints.put(this.end, ends); ++ } ++ ends.add(this); ++ } ++ ++ @Override ++ public int compareTo(LVTVariable o) { ++ if (o.end > end) return -1; ++ if (o.end < end) return 1; ++ if (o.index > index) return -1; ++ if (o.index < index) return 1; ++ return 0; ++ } ++ } + private Map mapVarNames = Collections.emptyMap(); + ++ private Map> endpoints = Collections.emptyMap(); ++ private ArrayList allLVT; ++ + @Override + public void initContent(ConstantPool pool) throws IOException { + DataInputFullStream data = stream(); + + int len = data.readUnsignedShort(); ++ boolean isLVTT = this.getName().equals(ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE); + if (len > 0) { + mapVarNames = new HashMap(len); ++ endpoints = new HashMap>(len); ++ allLVT = new ArrayList(len); + for (int i = 0; i < len; i++) { +- data.discard(4); ++ int start = data.readUnsignedShort(); ++ int vlen = data.readUnsignedShort(); + int nameIndex = data.readUnsignedShort(); +- data.discard(2); ++ int descIndex = data.readUnsignedShort(); // either descriptor or signature + int varIndex = data.readUnsignedShort(); ++ LVTVariable v = new LVTVariable(pool.getPrimitiveConstant(nameIndex).getString(), pool.getPrimitiveConstant(descIndex).getString(),start,start+vlen,varIndex,isLVTT); + mapVarNames.put(varIndex, pool.getPrimitiveConstant(nameIndex).getString()); ++ allLVT.add(v); ++ v.addTo(endpoints); + } + } + else { +@@ -59,6 +123,15 @@ public class StructLocalVariableTableAttribute extends StructGeneralAttribute { + + public void addLocalVariableTable(StructLocalVariableTableAttribute attr) { + mapVarNames.putAll(attr.getMapVarNames()); ++ for (LVTVariable other : attr.allLVT) { ++ int idx = allLVT.indexOf(other); ++ if (idx < 0) { ++ allLVT.add(other); ++ } else { ++ LVTVariable mine = allLVT.get(idx); ++ mine.merge(other); ++ } ++ } + } + + public Map getMapVarNames() { +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0008-LVT-Fixes-and-Support-for-Enhanced-For-loop-detectio.patch b/FernFlower-Patches/0008-LVT-Fixes-and-Support-for-Enhanced-For-loop-detectio.patch deleted file mode 100644 index bf8867f..0000000 --- a/FernFlower-Patches/0008-LVT-Fixes-and-Support-for-Enhanced-For-loop-detectio.patch +++ /dev/null @@ -1,4949 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Tue, 11 Apr 2017 22:54:20 -0700 -Subject: [PATCH] LVT Fixes and Support for Enhanced For loop detection. - - -diff --git a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -index ec59ac3c399dd1609663bc9444a098285b5dc48a..33906d3a433e4421bbf41c6aed5ff566a69a904a 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -@@ -8,7 +8,6 @@ import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector; - import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; - import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; --import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; - import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -@@ -39,6 +38,7 @@ public class ClassWrapper { - public void init() { - DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct); - DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_WRAPPER, this); -+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, DecompilerContext.getClassProcessor().getMapRootClasses().get(classStruct.qualifiedName)); - DecompilerContext.getLogger().startClass(classStruct.qualifiedName); - - int maxSec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString()); -@@ -162,8 +162,9 @@ public class ClassWrapper { - StructLocalVariableTableAttribute attr = mt.getLocalVariableAttr(); - if (attr != null) { - // only param names here -- varProc.setDebugVarNames(attr.getMapParamNames()); -+ varProc.setDebugVarNames(attr.getMapNames()); - -+ /* - // the rest is here - methodWrapper.getOrBuildGraph().iterateExprents(exprent -> { - List lst = exprent.getAllExprents(true); -@@ -179,6 +180,7 @@ public class ClassWrapper { - }); - return 0; - }); -+ */ - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java -index 80f024eb8e069cc4d208a9b79dbc7edf67161ec7..fa4b5ed56fa58f2d864ea3acd758a36fa8e23e7a 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java -@@ -11,7 +11,13 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper; - import org.jetbrains.java.decompiler.modules.decompiler.*; - import org.jetbrains.java.decompiler.modules.decompiler.deobfuscator.ExceptionDeobfuscator; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.MonitorExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; - import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; - import org.jetbrains.java.decompiler.struct.StructClass; - import org.jetbrains.java.decompiler.struct.StructMethod; -@@ -125,11 +131,11 @@ public class MethodProcessorRunnable implements Runnable { - ExceptionDeobfuscator.insertDummyExceptionHandlerBlocks(graph, mt.getBytecodeVersion()); - } - -- RootStatement root = DomHelper.parseGraph(graph); -+ RootStatement root = DomHelper.parseGraph(graph, mt); - - FinallyProcessor fProc = new FinallyProcessor(md, varProc); - while (fProc.iterateGraph(cl, mt, root, graph)) { -- root = DomHelper.parseGraph(graph); -+ root = DomHelper.parseGraph(graph, mt); - } - - // remove synchronized exception handler -@@ -153,15 +159,26 @@ public class MethodProcessorRunnable implements Runnable { - stackProc.simplifyStackVars(root, mt, cl); - varProc.setVarVersions(root); - } -- while (new PPandMMHelper().findPPandMM(root)); -+ while (new PPandMMHelper(varProc).findPPandMM(root)); - - while (true) { - LabelHelper.cleanUpEdges(root); - -- do { -+ while (true) { -+ if (EliminateLoopsHelper.eliminateLoops(root, cl)) { -+ continue; -+ } -+ - MergeHelper.enhanceLoops(root); -+ -+ if (LoopExtractHelper.extractLoops(root)) { -+ continue; -+ } -+ -+ if (!IfHelper.mergeAllIfs(root)) { -+ break; -+ } - } -- while (LoopExtractHelper.extractLoops(root) || IfHelper.mergeAllIfs(root)); - - if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) { - if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) { -@@ -177,6 +194,12 @@ public class MethodProcessorRunnable implements Runnable { - continue; - } - -+ // this has to be done last so it does not screw up the formation of for loops -+ if (MergeHelper.makeDoWhileLoops(root)) { -+ LabelHelper.cleanUpEdges(root); -+ LabelHelper.identifyLabels(root); -+ } -+ - // initializer may have at most one return point, so no transformation of method exits permitted - if (isInitializer || !ExitHelper.condenseExits(root)) { - break; -@@ -192,6 +215,8 @@ public class MethodProcessorRunnable implements Runnable { - - SecondaryFunctionsHelper.identifySecondaryFunctions(root, varProc); - -+ cleanSynchronizedVar(root); -+ - varProc.setVarDefinitions(root); - - // must be the last invocation, because it makes the statement structure inconsistent -@@ -215,4 +240,29 @@ public class MethodProcessorRunnable implements Runnable { - public boolean isFinished() { - return finished; - } -+ -+ public static void cleanSynchronizedVar(Statement stat) { -+ for (Statement st : stat.getStats()) { -+ cleanSynchronizedVar(st); -+ } -+ -+ if (stat.type == Statement.StatementType.SYNCHRONIZED) { -+ SynchronizedStatement sync = (SynchronizedStatement)stat; -+ if (sync.getHeadexprentList().get(0).type == Exprent.EXPRENT_MONITOR) { -+ MonitorExprent mon = (MonitorExprent)sync.getHeadexprentList().get(0); -+ for (Exprent e : sync.getFirst().getExprents()) { -+ if (e.type == Exprent.EXPRENT_ASSIGNMENT) { -+ AssignmentExprent ass = (AssignmentExprent)e; -+ if (ass.getLeft().type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)ass.getLeft(); -+ if (ass.getRight().equals(mon.getValue()) && !var.isVarReferenced(stat.getParent())) { -+ sync.getFirst().getExprents().remove(e); -+ break; -+ } -+ } -+ } -+ } -+ } -+ } -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index 7d41769adee0974a02e0ef5a0518f9f9e53c8b58..bb2d0f0eb067a92472dcd8d69a0029d15c34c520 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -@@ -22,6 +22,7 @@ import org.jetbrains.java.decompiler.struct.StructField; - import org.jetbrains.java.decompiler.struct.StructMethod; - import org.jetbrains.java.decompiler.struct.attr.StructEnclosingMethodAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; -+import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute.LocalVariable; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.util.DotExporter; -@@ -114,6 +115,7 @@ public class NestedClassProcessor { - } - - Map mapNewNames = new HashMap<>(); -+ Map lvts = new HashMap<>(); - - enclosingMethod.getOrBuildGraph().iterateExprents(exprent -> { - List lst = exprent.getAllExprents(true); -@@ -138,6 +140,7 @@ public class NestedClassProcessor { - - if (param.type == Exprent.EXPRENT_VAR) { - mapNewNames.put(varVersion, enclosingMethod.varproc.getVarName(new VarVersionPair((VarExprent)param))); -+ lvts.put(varVersion, ((VarExprent)param).getLVT()); - } - } - else { -@@ -161,8 +164,26 @@ public class NestedClassProcessor { - method.setOuterVarNames.addAll(setNewOuterNames); - - for (Entry entry : mapNewNames.entrySet()) { -- method.varproc.setVarName(entry.getKey(), entry.getValue()); -+ VarVersionPair pair = entry.getKey(); -+ LocalVariable lvt = lvts.get(pair); -+ -+ method.varproc.setVarName(pair, entry.getValue()); -+ if (lvt != null) { -+ method.varproc.setVarLVT(pair, lvt); -+ } - } -+ -+ method.getOrBuildGraph().iterateExprentsDeep(exp -> { -+ if (exp.type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)exp; -+ LocalVariable lv = lvts.get(var.getVarVersionPair()); -+ if (lv != null) -+ var.setLVT(lv); -+ else if (mapNewNames.containsKey(var.getVarVersionPair())) -+ var.setLVT(null); -+ } -+ return 0; -+ }); - } - - private static void checkNotFoundClasses(ClassNode root, ClassNode node) { -@@ -400,6 +421,7 @@ public class NestedClassProcessor { - if (method.root != null) { // neither abstract nor native - Map mapNewNames = new HashMap<>(); // local var names - Map mapNewTypes = new HashMap<>(); // local var types -+ Map mapNewLVTs = new HashMap<>(); // local var table entries - - Map mapParamsToNewVars = new HashMap<>(); - if (method.synthParameters != null) { -@@ -414,15 +436,17 @@ public class NestedClassProcessor { - - String varName = null; - VarType varType = null; -+ LocalVariable varLVT = null; - - if (child.type != ClassNode.CLASS_MEMBER) { - varName = enclosingMethod.varproc.getVarName(pair); - varType = enclosingMethod.varproc.getVarType(pair); -+ varLVT = enclosingMethod.varproc.getVarLVT(pair); - - enclosingMethod.varproc.setVarFinal(pair, VarProcessor.VAR_EXPLICIT_FINAL); - } - -- if (pair.var == -1 || "this".equals(varName)) { -+ if (pair.var == -1 || "this".equals(varName) || (varLVT != null && "this".equals(varLVT.getName()))) { - if (parent.simpleName == null) { - // anonymous enclosing class, no access to this - varName = VarExprent.VAR_NAMELESS_ENCLOSURE; -@@ -430,11 +454,15 @@ public class NestedClassProcessor { - else { - varName = parent.simpleName + ".this"; - } -+ if (varLVT != null) { -+ varLVT = varLVT.rename(varName); -+ } - method.varproc.getThisVars().put(newVar, parent.classStruct.qualifiedName); - } - - mapNewNames.put(newVar, varName); - mapNewTypes.put(newVar, varType); -+ mapNewLVTs.put(newVar, varLVT); - } - - varIndex += md.params[index++].getStackSize(); -@@ -450,17 +478,19 @@ public class NestedClassProcessor { - - String varName = null; - VarType varType = null; -+ LocalVariable varLVT = null; - - if (classNode.type != ClassNode.CLASS_MEMBER) { - MethodWrapper enclosing_method = classNode.parent.getWrapper().getMethods().getWithKey(classNode.enclosingMethod); - - varName = enclosing_method.varproc.getVarName(entry.getValue()); - varType = enclosing_method.varproc.getVarType(entry.getValue()); -+ varLVT = enclosing_method.varproc.getVarLVT(entry.getValue()); - - enclosing_method.varproc.setVarFinal(entry.getValue(), VarProcessor.VAR_EXPLICIT_FINAL); - } - -- if (entry.getValue().var == -1 || "this".equals(varName)) { -+ if (entry.getValue().var == -1 || "this".equals(varName) || (varLVT != null && "this".equals(varLVT.getName()))) { - if (classNode.parent.simpleName == null) { - // anonymous enclosing class, no access to this - varName = VarExprent.VAR_NAMELESS_ENCLOSURE; -@@ -468,11 +498,15 @@ public class NestedClassProcessor { - else { - varName = classNode.parent.simpleName + ".this"; - } -+ if (varLVT != null) { -+ varLVT = varLVT.rename(varName); -+ } - method.varproc.getThisVars().put(newVar, classNode.parent.classStruct.qualifiedName); - } - - mapNewNames.put(newVar, varName); - mapNewTypes.put(newVar, varType); -+ mapNewLVTs.put(newVar, varLVT); - - // hide synthetic field - if (classNode == child) { // fields higher up the chain were already handled with their classes -@@ -491,16 +525,20 @@ public class NestedClassProcessor { - for (Entry entry : mapNewNames.entrySet()) { - VarVersionPair pair = entry.getKey(); - VarType type = mapNewTypes.get(pair); -+ LocalVariable lvt = mapNewLVTs.get(pair); - - method.varproc.setVarName(pair, entry.getValue()); - if (type != null) { - method.varproc.setVarType(pair, type); - } -+ if (lvt != null) { -+ method.varproc.setVarLVT(pair, lvt); -+ } - } - -- method.getOrBuildGraph().iterateExprents(new DirectGraph.ExprentIterator() { -+ iterateExprents(method.getOrBuildGraph(), new ExprentIteratorWithReplace() { - @Override -- public int processExprent(Exprent exprent) { -+ public Exprent processExprent(Exprent exprent) { - if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { - AssignmentExprent assignExpr = (AssignmentExprent)exprent; - if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) { -@@ -508,7 +546,7 @@ public class NestedClassProcessor { - String qName = child.classStruct.qualifiedName; - if (fExpr.getClassname().equals(qName) && // process this class only - mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(qName, fExpr.getName(), fExpr.getDescriptor().descriptorString))) { -- return 2; -+ return null; - } - } - } -@@ -520,13 +558,13 @@ public class NestedClassProcessor { - if (invokeExpr.getFuncType() == InvocationExprent.TYPE_INIT) { - // invocation of the super constructor in an anonymous class - child.superInvocation = invokeExpr; // FIXME: save original names of parameters -- return 2; -+ return null; - } - } - -- replaceExprent(exprent); -+ Exprent ret = replaceExprent(exprent); - -- return 0; -+ return ret == null ? exprent : ret; - } - - private Exprent replaceExprent(Exprent exprent) { -@@ -535,7 +573,12 @@ public class NestedClassProcessor { - if (mapParamsToNewVars.containsKey(varIndex)) { - VarVersionPair newVar = mapParamsToNewVars.get(varIndex); - method.varproc.getExternalVars().add(newVar); -- return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode); -+ VarExprent ret = new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode); -+ LocalVariable lvt = method.varproc.getVarLVT(newVar); -+ if (lvt != null) { -+ ret.setLVT(lvt); -+ } -+ return ret; - } - } - else if (exprent.type == Exprent.EXPRENT_FIELD) { -@@ -543,10 +586,15 @@ public class NestedClassProcessor { - String key = InterpreterUtil.makeUniqueKey(fExpr.getClassname(), fExpr.getName(), fExpr.getDescriptor().descriptorString); - if (mapFieldsToNewVars.containsKey(key)) { - //if(fExpr.getClassname().equals(child.classStruct.qualifiedName) && -- // mapFieldsToNewVars.containsKey(key)) { -+ // mapFieldsToNewVars.containsKey(key)) { - VarVersionPair newVar = mapFieldsToNewVars.get(key); - method.varproc.getExternalVars().add(newVar); -- return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode); -+ VarExprent ret = new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode); -+ LocalVariable lvt = method.varproc.getVarLVT(newVar); -+ if (lvt != null) { -+ ret.setLVT(lvt); -+ } -+ return ret; - } - } - -@@ -911,4 +959,41 @@ public class NestedClassProcessor { - return fieldKey.hashCode() + varPair.hashCode(); - } - } --} -\ No newline at end of file -+ -+ private static interface ExprentIteratorWithReplace { -+ // null - remove exprent -+ // ret != exprent - replace exprent with ret -+ Exprent processExprent(Exprent exprent); -+ } -+ -+ private static void iterateExprents(DirectGraph graph, ExprentIteratorWithReplace iter) { -+ LinkedList stack = new LinkedList<>(); -+ stack.add(graph.first); -+ -+ HashSet setVisited = new HashSet<>(); -+ -+ while (!stack.isEmpty()) { -+ -+ DirectNode node = stack.removeFirst(); -+ -+ if (setVisited.contains(node)) { -+ continue; -+ } -+ setVisited.add(node); -+ -+ for (int i = 0; i < node.exprents.size(); i++) { -+ Exprent res = iter.processExprent(node.exprents.get(i)); -+ -+ if (res == null) { -+ node.exprents.remove(i); -+ i--; -+ } -+ else if (res != node.exprents.get(i)) { -+ node.exprents.set(i, res); -+ } -+ } -+ -+ stack.addAll(node.successors); -+ } -+ } -+} -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java -index 277e792a2856334970bafe0661582a8c8d09ad5a..ceffabcd6434f5504e7aaf89878abe7012cfcaa5 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java -@@ -12,6 +12,8 @@ import org.jetbrains.java.decompiler.modules.decompiler.decompose.FastExtendedPo - import org.jetbrains.java.decompiler.modules.decompiler.deobfuscator.IrreducibleCFGDeobfuscator; - import org.jetbrains.java.decompiler.modules.decompiler.stats.*; - import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement.StatementType; -+import org.jetbrains.java.decompiler.struct.StructMethod; -+import org.jetbrains.java.decompiler.util.DotExporter; - import org.jetbrains.java.decompiler.util.FastFixedSetFactory; - import org.jetbrains.java.decompiler.util.FastFixedSetFactory.FastFixedSet; - import org.jetbrains.java.decompiler.util.VBStyleCollection; -@@ -190,17 +192,12 @@ public final class DomHelper { - return ret; - } - -- public static RootStatement parseGraph(ControlFlowGraph graph) { -+ public static RootStatement parseGraph(ControlFlowGraph graph, StructMethod mt) { - - RootStatement root = graphToStatement(graph); - - if (!processStatement(root, new LinkedHashMap<>())) { -- -- // try { -- // DotExporter.toDotFile(root.getFirst().getStats().get(13), new File("c:\\Temp\\stat1.dot")); -- // } catch (Exception ex) { -- // ex.printStackTrace(); -- // } -+ DotExporter.toDotFile(graph, mt, "parseGraphFail", true); - throw new RuntimeException("parsing failure!"); - } - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java -new file mode 100644 -index 0000000000000000000000000000000000000000..82c960ee29c4babfe77381df3a4a46716c68e401 ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java -@@ -0,0 +1,199 @@ -+// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -+package org.jetbrains.java.decompiler.modules.decompiler; -+ -+import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; -+import org.jetbrains.java.decompiler.struct.StructClass; -+ -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.HashSet; -+import java.util.List; -+import java.util.Set; -+ -+ -+public class EliminateLoopsHelper { -+ -+ public static boolean eliminateLoops(Statement root, StructClass cl) { -+ -+ boolean ret = eliminateLoopsRec(root); -+ -+ if(ret) { -+ SequenceHelper.condenseSequences(root); -+ -+ Set setReorderedIfs = new HashSet<>(); -+ -+ SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(false); -+ while(sehelper.simplifyStackVarsStatement(root, setReorderedIfs, null, cl)) { -+ SequenceHelper.condenseSequences(root); -+ } -+ } -+ -+ return ret; -+ } -+ -+ private static boolean eliminateLoopsRec(Statement stat) { -+ -+ for (Statement st : stat.getStats()) { -+ if (eliminateLoopsRec(st)) { -+ return true; -+ } -+ } -+ -+ if (stat.type == Statement.StatementType.DO && isLoopRedundant((DoStatement)stat)) { -+ return true; -+ } -+ -+ return false; -+ } -+ -+ private static boolean isLoopRedundant(DoStatement loop) { -+ -+ if (loop.getLoopType() != DoStatement.LoopType.DO) { -+ return false; -+ } -+ -+ // get parent loop if exists -+ Statement parentloop = loop.getParent(); -+ while (parentloop != null && parentloop.type != Statement.StatementType.DO) { -+ parentloop = parentloop.getParent(); -+ } -+ -+ if (parentloop == null || parentloop.getBasichead() != loop.getBasichead()) { -+ return false; -+ } -+ -+ // collect relevant break edges -+ List lstBreakEdges = new ArrayList<>(); -+ for (StatEdge edge : loop.getLabelEdges()) { -+ if (edge.getType() == StatEdge.EdgeType.BREAK) { // all break edges are explicit because of LOOP_DO type -+ lstBreakEdges.add(edge); -+ } -+ } -+ -+ -+ Statement loopcontent = loop.getFirst(); -+ -+ boolean firstok = loopcontent.getAllSuccessorEdges().isEmpty(); -+ if (!firstok) { -+ StatEdge edge = loopcontent.getAllSuccessorEdges().get(0); -+ firstok = (edge.closure == loop && edge.getType() == StatEdge.EdgeType.BREAK); -+ if (firstok) { -+ lstBreakEdges.remove(edge); -+ } -+ } -+ -+ -+ if (!lstBreakEdges.isEmpty()) { -+ if (firstok) { -+ -+ HashMap statLabeled = new HashMap<>(); -+ List lstEdgeClosures = new ArrayList<>(); -+ -+ for (StatEdge edge : lstBreakEdges) { -+ Statement minclosure = LowBreakHelper.getMinClosure(loopcontent, edge.getSource()); -+ lstEdgeClosures.add(minclosure); -+ } -+ -+ int precount = loop.isLabeled() ? 1 : 0; -+ for (Statement st : lstEdgeClosures) { -+ if (!statLabeled.containsKey(st.id)) { -+ boolean btemp = st.isLabeled(); -+ precount += btemp ? 1 : 0; -+ statLabeled.put(st.id, btemp); -+ } -+ } -+ -+ for (int i = 0; i < lstBreakEdges.size(); i++) { -+ Statement st = lstEdgeClosures.get(i); -+ statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id)); -+ } -+ -+ for (int i = 0; i < lstBreakEdges.size(); i++) { -+ lstEdgeClosures.set(i, getMaxBreakLift(lstEdgeClosures.get(i), lstBreakEdges.get(i), statLabeled, loop)); -+ } -+ -+ statLabeled.clear(); -+ for (Statement st : lstEdgeClosures) { -+ statLabeled.put(st.id, st.isLabeled()); -+ } -+ -+ for (int i = 0; i < lstBreakEdges.size(); i++) { -+ Statement st = lstEdgeClosures.get(i); -+ statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id)); -+ } -+ -+ long postcount = statLabeled.values().stream().filter(Boolean::booleanValue).count(); -+ -+ if (precount <= postcount) { -+ return false; -+ } -+ else { -+ for (int i = 0; i < lstBreakEdges.size(); i++) { -+ lstEdgeClosures.get(i).addLabeledEdge(lstBreakEdges.get(i)); -+ } -+ } -+ } -+ else { -+ return false; -+ } -+ } -+ -+ eliminateLoop(loop, parentloop); -+ -+ return true; -+ } -+ -+ private static Statement getMaxBreakLift(Statement stat, StatEdge edge, HashMap statLabeled, Statement max) { -+ -+ Statement closure = stat; -+ Statement newclosure = stat; -+ -+ while ((newclosure = getNextBreakLift(newclosure, edge, statLabeled, max)) != null) { -+ closure = newclosure; -+ } -+ -+ return closure; -+ } -+ -+ private static Statement getNextBreakLift(Statement stat, StatEdge edge, HashMap statLabeled, Statement max) { -+ -+ Statement closure = stat.getParent(); -+ -+ while (closure != null && closure != max && !closure.containsStatementStrict(edge.getDestination())) { -+ -+ boolean edge_labeled = LowBreakHelper.isBreakEdgeLabeled(edge.getSource(), closure); -+ boolean stat_labeled = statLabeled.containsKey(closure.id) ? statLabeled.get(closure.id) : closure.isLabeled(); -+ -+ if (stat_labeled || !edge_labeled) { -+ return closure; -+ } -+ -+ closure = closure.getParent(); -+ } -+ -+ return null; -+ } -+ -+ private static void eliminateLoop(Statement loop, Statement parentloop) { -+ -+ // remove the last break edge, if exists -+ Statement loopcontent = loop.getFirst(); -+ if (!loopcontent.getSuccessorEdges(StatEdge.EdgeType.BREAK).isEmpty()) { -+ loopcontent.removeSuccessor(loopcontent.getSuccessorEdges(StatEdge.EdgeType.BREAK).get(0)); -+ } -+ -+ // move continue edges to the parent loop -+ List lst = new ArrayList<>(loop.getLabelEdges()); -+ for (StatEdge edge : lst) { -+ loop.removePredecessor(edge); -+ edge.getSource().changeEdgeNode(StatEdge.EdgeDirection.FORWARD, edge, parentloop); -+ parentloop.addPredecessor(edge); -+ -+ parentloop.addLabeledEdge(edge); -+ } -+ -+ // replace loop with its content -+ loop.getParent().replaceStatement(loop, loopcontent); -+ } -+} -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java -index c5ccfd1a659461646494c3796528767d0ba089c8..ef96a3f610c7fe1af746aa1d8663ba7adb530d8b 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java -@@ -175,7 +175,7 @@ public final class ExitHelper { - private static Statement isExitEdge(StatEdge edge) { - Statement dest = edge.getDestination(); - -- if (edge.getType() == EdgeType.BREAK && dest.type == StatementType.BASIC_BLOCK && edge.explicit && (edge.labeled || isOnlyEdge(edge))) { -+ if (edge.getType() == EdgeType.BREAK && dest.type == StatementType.BASIC_BLOCK && edge.explicit && (edge.labeled || isOnlyEdge(edge)) && edge.canInline) { - List data = dest.getExprents(); - - if (data != null && data.size() == 1) { -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -index 3b10e5b29ff9e344815592e533b6b04891fe294c..a242aa9e74698b14e20e27d655a3c8ae141ee2f5 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -@@ -315,7 +315,9 @@ public class ExprProcessor implements CodeConstants { - case opc_fload: - case opc_dload: - case opc_aload: -- pushEx(stack, exprList, new VarExprent(instr.operand(0), varTypes[instr.opcode - opc_iload], varProcessor, offsets)); -+ VarExprent varExprent = new VarExprent(instr.operand(0), varTypes[instr.opcode - opc_iload], varProcessor, offsets); -+ varProcessor.findLVT(varExprent, offset + instr.length); -+ pushEx(stack, exprList, varExprent); - break; - case opc_iaload: - case opc_laload: -@@ -342,6 +344,7 @@ public class ExprProcessor implements CodeConstants { - offsets.set(offset, offset + instr.length); - } - VarExprent left = new VarExprent(varIndex, varTypes[instr.opcode - opc_istore], varProcessor, offsets); -+ varProcessor.findLVT(left, offset + instr.length); - exprList.add(new AssignmentExprent(left, value, offsets)); - break; - } -@@ -404,6 +407,7 @@ public class ExprProcessor implements CodeConstants { - break; - case opc_iinc: { - VarExprent varExpr = new VarExprent(instr.operand(0), VarType.VARTYPE_INT, varProcessor, offsets); -+ varProcessor.findLVT(varExpr, offset + instr.length); - int type = instr.operand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD; - List operands = Arrays.asList(varExpr.copy(), new ConstExprent(VarType.VARTYPE_INT, Math.abs(instr.operand(1)), null)); - exprList.add(new AssignmentExprent(varExpr, new FunctionExprent(type, operands, offsets), offsets)); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java -index 271ab6a217c507d2fae72fb8aa2f38ebd054c80a..1f648ba330f9728c807c04f79d22894b03334f66 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java -@@ -121,6 +121,9 @@ public final class InlineSingleBlockHelper { - StatEdge edge = lst.get(0); - - if (sameCatchRanges(edge)) { -+ if (!edge.canInline) { -+ return false; //Dirty hack, but lets do it! -+ } - if (!edge.explicit) { - for (int i = index; i < seq.getStats().size(); i++) { - if (!noExitLabels(seq.getStats().get(i), seq)) { -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java -index c4fd9dd28fa7b587cf696187312f2988588ba02b..1743e96a47775011c65a10cddf5a7226ef656473 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java -@@ -12,6 +12,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement.Statemen - - import java.util.ArrayList; - import java.util.Arrays; -+import java.util.List; - import java.util.Set; - - -@@ -67,16 +68,33 @@ public final class LoopExtractHelper { - return false; - } - -+ List stats = new ArrayList<>(); - for (StatEdge edge : stat.getLabelEdges()) { - if (edge.getType() != EdgeType.CONTINUE && edge.getDestination().type != StatementType.DUMMY_EXIT) { -+ if (edge.getType() == EdgeType.BREAK && isExternStatement(stat, edge.getSource(), edge.getSource())) { -+ stats.add(edge.getSource()); -+ } -+ else { -+ return false; -+ } -+ } -+ } -+ -+ if (stats.size() > 0) { // In this case prioritize first to help the Loop enhancer -+ if (stat.getParent().getStats().getLast() != stat) { - return false; - } - } - -- return extractLastIf(stat) || extractFirstIf(stat); -+ if (!extractFirstIf(stat, stats)) { -+ return extractLastIf(stat, stats); -+ } -+ else { -+ return true; -+ } - } - -- private static boolean extractLastIf(DoStatement stat) { -+ private static boolean extractLastIf(DoStatement stat, List stats) { - - // search for an if condition at the end of the loop - Statement last = stat.getFirst(); -@@ -97,6 +115,19 @@ public final class LoopExtractHelper { - - if (set.isEmpty()) { // no direct continues in a do{}while loop - if (isExternStatement(stat, ifstat, ifstat)) { -+ Statement first = stat.getFirst(); -+ while (first.type == Statement.StatementType.SEQUENCE) { -+ first = first.getFirst(); -+ } -+ if (first.type == Statement.StatementType.DO && ((DoStatement)first).getLoopType() == DoStatement.LoopType.DO) { -+ return false; -+ } -+ -+ for (Statement s : stats) { -+ if (!ifstat.containsStatement(s)) { -+ return false; -+ } -+ } - extractIfBlock(stat, lastif); - return true; - } -@@ -107,7 +138,7 @@ public final class LoopExtractHelper { - return false; - } - -- private static boolean extractFirstIf(DoStatement stat) { -+ private static boolean extractFirstIf(DoStatement stat, List stats) { - - // search for an if condition at the entrance of the loop - Statement first = stat.getFirst(); -@@ -125,6 +156,11 @@ public final class LoopExtractHelper { - Statement ifstat = firstif.getIfstat(); - - if (isExternStatement(stat, ifstat, ifstat)) { -+ for (Statement s : stats) { -+ if (!ifstat.containsStatement(s)) { -+ return false; -+ } -+ } - extractIfBlock(stat, firstif); - return true; - } -@@ -185,5 +221,10 @@ public final class LoopExtractHelper { - loop.addPredecessor(edge); - } - } -+ -+ List link = target.getPredecessorEdges(StatEdge.EdgeType.BREAK); -+ if (link.size() == 1) { -+ link.get(0).canInline = false; -+ } - } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java -new file mode 100644 -index 0000000000000000000000000000000000000000..04f0a2768d2a943475df28a17389407b3dad7a48 ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java -@@ -0,0 +1,194 @@ -+// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -+package org.jetbrains.java.decompiler.modules.decompiler; -+ -+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement; -+ -+import java.util.List; -+ -+public class LowBreakHelper { -+ -+ public static void lowBreakLabels(Statement root) { -+ -+ lowBreakLabelsRec(root); -+ -+ liftBreakLabels(root); -+ } -+ -+ private static void lowBreakLabelsRec(Statement stat) { -+ -+ while (true) { -+ -+ boolean found = false; -+ -+ for (StatEdge edge : stat.getLabelEdges()) { -+ if (edge.getType() == StatEdge.EdgeType.BREAK) { -+ Statement minclosure = getMinClosure(stat, edge.getSource()); -+ if (minclosure != stat) { -+ minclosure.addLabeledEdge(edge); -+ edge.labeled = isBreakEdgeLabeled(edge.getSource(), minclosure); -+ found = true; -+ break; -+ } -+ } -+ } -+ -+ if (!found) { -+ break; -+ } -+ } -+ -+ for (Statement st : stat.getStats()) { -+ lowBreakLabelsRec(st); -+ } -+ } -+ -+ public static boolean isBreakEdgeLabeled(Statement source, Statement closure) { -+ -+ if (closure.type == Statement.StatementType.DO || closure.type == Statement.StatementType.SWITCH) { -+ -+ Statement parent = source.getParent(); -+ -+ if (parent == closure) { -+ return false; -+ } -+ else { -+ return isBreakEdgeLabeled(parent, closure) || -+ (parent.type == Statement.StatementType.DO || parent.type == Statement.StatementType.SWITCH); -+ } -+ } -+ else { -+ return true; -+ } -+ } -+ -+ public static Statement getMinClosure(Statement closure, Statement source) { -+ -+ while (true) { -+ -+ Statement newclosure = null; -+ -+ switch (closure.type) { -+ case SEQUENCE: -+ Statement last = closure.getStats().getLast(); -+ -+ if (isOkClosure(closure, source, last)) { -+ newclosure = last; -+ } -+ break; -+ case IF: -+ IfStatement ifclosure = (IfStatement)closure; -+ if (isOkClosure(closure, source, ifclosure.getIfstat())) { -+ newclosure = ifclosure.getIfstat(); -+ } -+ else if (isOkClosure(closure, source, ifclosure.getElsestat())) { -+ newclosure = ifclosure.getElsestat(); -+ } -+ break; -+ case TRY_CATCH: -+ for (Statement st : closure.getStats()) { -+ if (isOkClosure(closure, source, st)) { -+ newclosure = st; -+ break; -+ } -+ } -+ break; -+ case SYNCHRONIZED: -+ Statement body = ((SynchronizedStatement)closure).getBody(); -+ -+ if (isOkClosure(closure, source, body)) { -+ newclosure = body; -+ } -+ } -+ -+ if (newclosure == null) { -+ break; -+ } -+ -+ closure = newclosure; -+ } -+ -+ return closure; -+ } -+ -+ private static boolean isOkClosure(Statement closure, Statement source, Statement stat) { -+ -+ boolean ok = false; -+ -+ if (stat != null && stat.containsStatementStrict(source)) { -+ -+ List lst = stat.getAllSuccessorEdges(); -+ -+ ok = lst.isEmpty(); -+ if (!ok) { -+ StatEdge edge = lst.get(0); -+ ok = (edge.closure == closure && edge.getType() == StatEdge.EdgeType.BREAK); -+ } -+ } -+ -+ return ok; -+ } -+ -+ -+ private static void liftBreakLabels(Statement stat) { -+ -+ for (Statement st : stat.getStats()) { -+ liftBreakLabels(st); -+ } -+ -+ -+ while (true) { -+ -+ boolean found = false; -+ -+ for (StatEdge edge : stat.getLabelEdges()) { -+ if (edge.explicit && edge.labeled && edge.getType() == StatEdge.EdgeType.BREAK) { -+ -+ Statement newclosure = getMaxBreakLift(stat, edge); -+ -+ if (newclosure != null) { -+ newclosure.addLabeledEdge(edge); -+ edge.labeled = isBreakEdgeLabeled(edge.getSource(), newclosure); -+ -+ found = true; -+ break; -+ } -+ } -+ } -+ -+ if (!found) { -+ break; -+ } -+ } -+ } -+ -+ private static Statement getMaxBreakLift(Statement stat, StatEdge edge) { -+ -+ Statement closure = null; -+ Statement newclosure = stat; -+ -+ while ((newclosure = getNextBreakLift(newclosure, edge)) != null) { -+ closure = newclosure; -+ } -+ -+ return closure; -+ } -+ -+ private static Statement getNextBreakLift(Statement stat, StatEdge edge) { -+ -+ Statement closure = stat.getParent(); -+ -+ while (closure != null && !closure.containsStatementStrict(edge.getDestination())) { -+ -+ boolean labeled = isBreakEdgeLabeled(edge.getSource(), closure); -+ if (closure.isLabeled() || !labeled) { -+ return closure; -+ } -+ -+ closure = closure.getParent(); -+ } -+ -+ return null; -+ } -+} -\ No newline at end of file -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java -index bbd7bd0cb42057638e765c5bb675b8d30b9b6796..9909e894e22fc8c19e05fae82b69db065b3be72d 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java -@@ -5,8 +5,13 @@ import org.jetbrains.java.decompiler.code.cfg.BasicBlock; - import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.main.collectors.CounterContainer; - import org.jetbrains.java.decompiler.modules.decompiler.StatEdge.EdgeType; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.ArrayExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; - import org.jetbrains.java.decompiler.modules.decompiler.stats.*; - import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement.LoopType; - import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement.StatementType; -@@ -47,15 +52,20 @@ public final class MergeHelper { - - // identify a while loop - if (matchWhile(stat)) { -- // identify a for loop - subtype of while -- matchFor(stat); -+ if (!matchForEach(stat)) { -+ matchFor(stat); -+ } - } - else { - // identify a do{}while loop -- matchDoWhile(stat); -+ //matchDoWhile(stat); -+ } -+ } -+ case WHILE -> { -+ if (!matchForEach(stat)) { -+ matchFor(stat); - } - } -- case WHILE -> matchFor(stat); - } - - return (stat.getLoopType() != oldLoop); -@@ -145,13 +155,14 @@ public final class MergeHelper { - if (firstif.iftype == IfStatement.IFTYPE_IF) { - if (firstif.getIfstat() == null) { - StatEdge ifedge = firstif.getIfEdge(); -- if (isDirectPath(stat, ifedge.getDestination())) { -+ -+ if (isDirectPath(stat, ifedge.getDestination()) || addContinueOrBreak(stat, ifedge)) { - // exit condition identified - stat.setLoopType(LoopType.WHILE); - - // negate condition (while header) - IfExprent ifexpr = (IfExprent)firstif.getHeadexprent().copy(); -- ifexpr.negateIf(); -+ ifexpr.negateIf(); - - if (stat.getConditionExprent() != null) { - ifexpr.getCondition().addBytecodeOffsets(stat.getConditionExprent().bytecode); -@@ -189,7 +200,7 @@ public final class MergeHelper { - return true; - } - } -- else { -+ //else { // fix infinite loops - StatEdge elseedge = firstif.getAllSuccessorEdges().get(0); - if (isDirectPath(stat, elseedge.getDestination())) { - // exit condition identified -@@ -243,7 +254,7 @@ public final class MergeHelper { - - return true; - } -- } -+ //} - } - } - } -@@ -328,6 +339,8 @@ public final class MergeHelper { - } - else { - preData = current.getNeighbours(EdgeType.REGULAR, EdgeDirection.BACKWARD).get(0); -+ // we're not a basic block, so we can't dive inside for exprents -+ if (preData.type != Statement.StatementType.BASIC_BLOCK) break; - preData = getLastDirectData(preData); - if (preData != null && !preData.getExprents().isEmpty()) { - initDoExprent = preData.getExprents().get(preData.getExprents().size() - 1); -@@ -366,12 +379,16 @@ public final class MergeHelper { - stat.setIncExprent(exp); - } - -- if (lastData.getExprents().isEmpty()) { -- List lst = lastData.getAllSuccessorEdges(); -+ cleanEmptyStatements(stat, lastData); -+ } -+ -+ private static void cleanEmptyStatements(DoStatement dostat, Statement stat) { -+ if (stat != null && stat.getExprents().isEmpty()) { -+ List lst = stat.getAllSuccessorEdges(); - if (!lst.isEmpty()) { -- lastData.removeSuccessor(lst.get(0)); -+ stat.removeSuccessor(lst.get(0)); - } -- removeLastEmptyStatement(stat, lastData); -+ removeLastEmptyStatement(dostat, stat); - } - } - -@@ -404,14 +421,346 @@ public final class MergeHelper { - return stat; - } - -- if (stat.type == StatementType.SEQUENCE) { -- for (int i = stat.getStats().size() - 1; i >= 0; i--) { -- Statement tmp = getLastDirectData(stat.getStats().get(i)); -- if (tmp == null || !tmp.getExprents().isEmpty()) { -- return tmp; -+ for (int i = stat.getStats().size() - 1; i >= 0; i--) { -+ Statement tmp = getLastDirectData(stat.getStats().get(i)); -+ if (tmp == null || !tmp.getExprents().isEmpty()) { -+ return tmp; -+ } -+ } -+ return null; -+ } -+ -+ private static boolean matchForEach(DoStatement stat) { -+ AssignmentExprent firstDoExprent = null; -+ AssignmentExprent[] initExprents = new AssignmentExprent[3]; -+ Statement firstData = null, preData = null, lastData = null; -+ Exprent lastExprent = null; -+ -+ // search for an initializing exprent -+ Statement current = stat; -+ while (true) { -+ Statement parent = current.getParent(); -+ if (parent == null) { -+ break; -+ } -+ -+ if (parent.type == Statement.StatementType.SEQUENCE) { -+ if (current == parent.getFirst()) { -+ current = parent; -+ } -+ else { -+ preData = current.getNeighbours(StatEdge.EdgeType.REGULAR, StatEdge.EdgeDirection.BACKWARD).get(0); -+ preData = getLastDirectData(preData); -+ if (preData != null && !preData.getExprents().isEmpty()) { -+ int size = preData.getExprents().size(); -+ for (int x = 0; x < initExprents.length; x++) { -+ if (size > x) { -+ Exprent exprent = preData.getExprents().get(size - 1 - x); -+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { -+ initExprents[x] = (AssignmentExprent)exprent; -+ } -+ } -+ } -+ } -+ break; - } - } -+ else { -+ break; -+ } -+ } -+ -+ firstData = getFirstDirectData(stat.getFirst()); -+ if (firstData != null && firstData.getExprents().get(0).type == Exprent.EXPRENT_ASSIGNMENT) { -+ firstDoExprent = (AssignmentExprent)firstData.getExprents().get(0); -+ } -+ lastData = getLastDirectData(stat.getFirst()); -+ if (lastData != null && !lastData.getExprents().isEmpty()) { -+ lastExprent = lastData.getExprents().get(lastData.getExprents().size() - 1); -+ } -+ -+ if (stat.getLoopType() == DoStatement.LoopType.WHILE && initExprents[0] != null && firstDoExprent != null) { -+ if (isIteratorCall(initExprents[0].getRight())) { -+ -+ //Streams mimic Iterable but arnt.. so explicitly disallow their enhancements -+ //TODO: Check inheritance for Iterable instead of just names? -+ InvocationExprent invc = (InvocationExprent)getUncast((initExprents[0]).getRight()); -+ if (invc.getClassName().contains("java/util/stream")) { -+ return false; -+ } -+ -+ if (!isHasNextCall(drillNots(stat.getConditionExprent())) || -+ firstDoExprent.type != Exprent.EXPRENT_ASSIGNMENT) { -+ return false; -+ } -+ -+ AssignmentExprent ass = firstDoExprent; -+ if ((!isNextCall(ass.getRight()) && !isNextUnboxing(ass.getRight())) || ass.getLeft().type != Exprent.EXPRENT_VAR) { -+ return false; -+ } -+ -+ InvocationExprent next = (InvocationExprent)getUncast(ass.getRight()); -+ if (isNextUnboxing(next)) -+ next = (InvocationExprent)getUncast(next.getInstance()); -+ InvocationExprent hnext = (InvocationExprent)getUncast(drillNots(stat.getConditionExprent())); -+ if (next.getInstance().type != Exprent.EXPRENT_VAR || -+ hnext.getInstance().type != Exprent.EXPRENT_VAR || -+ ((VarExprent)initExprents[0].getLeft()).isVarReferenced(stat, (VarExprent)next.getInstance(), (VarExprent)hnext.getInstance())) { -+ return false; -+ } -+ -+ InvocationExprent holder = (InvocationExprent)(initExprents[0]).getRight(); -+ -+ initExprents[0].getBytecodeRange(holder.getInstance().bytecode); -+ holder.getBytecodeRange(holder.getInstance().bytecode); -+ firstDoExprent.getBytecodeRange(ass.getLeft().bytecode); -+ ass.getRight().getBytecodeRange(ass.getLeft().bytecode); -+ if (stat.getIncExprent() != null) { -+ stat.getIncExprent().getBytecodeRange(holder.getInstance().bytecode); -+ } -+ if (stat.getInitExprent() != null) { -+ stat.getInitExprent().getBytecodeRange(ass.getLeft().bytecode); -+ } -+ -+ stat.setLoopType(DoStatement.LoopType.FOREACH); -+ stat.setInitExprent(ass.getLeft()); -+ stat.setIncExprent(holder.getInstance()); -+ preData.getExprents().remove(initExprents[0]); -+ firstData.getExprents().remove(firstDoExprent); -+ -+ if (initExprents[1] != null && initExprents[1].getLeft().type == Exprent.EXPRENT_VAR && -+ holder.getInstance().type == Exprent.EXPRENT_VAR) { -+ VarExprent copy = (VarExprent)initExprents[1].getLeft(); -+ VarExprent inc = (VarExprent)holder.getInstance(); -+ if (copy.getIndex() == inc.getIndex() && copy.getVersion() == inc.getVersion() && -+ !inc.isVarReferenced(stat.getTopParent(), copy) && !isNextCall(initExprents[1].getRight())) { -+ preData.getExprents().remove(initExprents[1]); -+ initExprents[1].getBytecodeRange(initExprents[1].getRight().bytecode); -+ stat.getIncExprent().getBytecodeRange(initExprents[1].getRight().bytecode); -+ stat.setIncExprent(initExprents[1].getRight()); -+ } -+ } -+ -+ return true; -+ } -+ else if (initExprents[1] != null) { -+ if (firstDoExprent.getRight().type != Exprent.EXPRENT_ARRAY || firstDoExprent.getLeft().type != Exprent.EXPRENT_VAR) { -+ return false; -+ } -+ -+ if (lastExprent == null || lastExprent.type != Exprent.EXPRENT_FUNCTION) { -+ return false; -+ } -+ -+ if (initExprents[0].getRight().type != Exprent.EXPRENT_CONST || -+ initExprents[1].getRight().type != Exprent.EXPRENT_FUNCTION || -+ stat.getConditionExprent().type != Exprent.EXPRENT_FUNCTION) { -+ return false; -+ } -+ -+ //FunctionExprent funcCond = (FunctionExprent)drillNots(stat.getConditionExprent()); //TODO: Verify this is counter < copy.length -+ FunctionExprent funcRight = (FunctionExprent)initExprents[1].getRight(); -+ FunctionExprent funcInc = (FunctionExprent)lastExprent; -+ ArrayExprent arr = (ArrayExprent)firstDoExprent.getRight(); -+ int incType = funcInc.getFuncType(); -+ -+ if (funcRight.getFuncType() != FunctionExprent.FUNCTION_ARRAY_LENGTH || -+ (incType != FunctionExprent.FUNCTION_PPI && incType != FunctionExprent.FUNCTION_IPP) || -+ arr.getIndex().type != Exprent.EXPRENT_VAR || -+ arr.getArray().type != Exprent.EXPRENT_VAR) { -+ return false; -+ } -+ -+ VarExprent index = (VarExprent)arr.getIndex(); -+ VarExprent array = (VarExprent)arr.getArray(); -+ VarExprent counter = (VarExprent)funcInc.getLstOperands().get(0); -+ -+ if (counter.getIndex() != index.getIndex() || -+ counter.getVersion() != index.getVersion()) { -+ return false; -+ } -+ -+ if (counter.isVarReferenced(stat.getFirst(), index)) { -+ return false; -+ } -+ -+ funcRight.getLstOperands().get(0).addBytecodeOffsets(initExprents[0].bytecode); -+ funcRight.getLstOperands().get(0).addBytecodeOffsets(initExprents[1].bytecode); -+ funcRight.getLstOperands().get(0).addBytecodeOffsets(lastExprent.bytecode); -+ firstDoExprent.getLeft().addBytecodeOffsets(firstDoExprent.bytecode); -+ firstDoExprent.getLeft().addBytecodeOffsets(initExprents[0].bytecode); -+ -+ stat.setLoopType(DoStatement.LoopType.FOREACH); -+ stat.setInitExprent(firstDoExprent.getLeft()); -+ stat.setIncExprent(funcRight.getLstOperands().get(0)); -+ preData.getExprents().remove(initExprents[0]); -+ preData.getExprents().remove(initExprents[1]); -+ firstData.getExprents().remove(firstDoExprent); -+ lastData.getExprents().remove(lastExprent); -+ -+ if (initExprents[2] != null && initExprents[2].getLeft().type == Exprent.EXPRENT_VAR) { -+ VarExprent copy = (VarExprent)initExprents[2].getLeft(); -+ if (copy.getIndex() == array.getIndex() && copy.getVersion() == array.getVersion()) { -+ preData.getExprents().remove(initExprents[2]); -+ initExprents[2].getRight().addBytecodeOffsets(initExprents[2].bytecode); -+ initExprents[2].getRight().addBytecodeOffsets(stat.getIncExprent().bytecode); -+ stat.setIncExprent(initExprents[2].getRight()); -+ } -+ } -+ -+ return true; -+ } -+ } -+ -+ //cleanEmptyStatements(stat, firstData); //TODO: Look into this and see what it does... -+ -+ return false; -+ } -+ -+ private static Exprent drillNots(Exprent exp) { -+ while (true) { -+ if (exp.type == Exprent.EXPRENT_FUNCTION) { -+ FunctionExprent fun = (FunctionExprent)exp; -+ if (fun.getFuncType() == FunctionExprent.FUNCTION_BOOL_NOT) { -+ exp = fun.getLstOperands().get(0); -+ } -+ else if (fun.getFuncType() == FunctionExprent.FUNCTION_EQ || -+ fun.getFuncType() == FunctionExprent.FUNCTION_NE) { -+ return fun.getLstOperands().get(0); -+ } -+ else { -+ return exp; -+ } -+ } -+ else { -+ return exp; -+ } -+ } -+ } -+ -+ private static Statement getFirstDirectData(Statement stat) { -+ if (stat.getExprents() != null && !stat.getExprents().isEmpty()) { -+ return stat; -+ } -+ -+ for (Statement tmp : stat.getStats()) { -+ Statement ret = getFirstDirectData(tmp); -+ if (ret != null) { -+ return ret; -+ } -+ } -+ return null; -+ } -+ -+ private static Exprent getUncast(Exprent exp) { -+ if (exp.type == Exprent.EXPRENT_FUNCTION) { -+ FunctionExprent func = (FunctionExprent)exp; -+ if (func.getFuncType() == FunctionExprent.FUNCTION_CAST) { -+ return getUncast(func.getLstOperands().get(0)); -+ } -+ } -+ return exp; -+ } -+ -+ private static InvocationExprent asInvocationExprent(Exprent exp) { -+ exp = getUncast(exp); -+ if (exp.type == Exprent.EXPRENT_INVOCATION) { -+ return (InvocationExprent) exp; - } - return null; - } --} -\ No newline at end of file -+ -+ private static boolean isIteratorCall(Exprent exp) { -+ final InvocationExprent iexp = asInvocationExprent(exp); -+ if (iexp == null) { -+ return false; -+ } -+ final org.jetbrains.java.decompiler.struct.gen.MethodDescriptor descriptor = iexp.getDescriptor(); -+ if (!DecompilerContext.getStructContext().instanceOf(descriptor.ret.getValue(), "java/util/Iterator")) { -+ return false; -+ } -+ final String name = iexp.getName(); -+ return "iterator".equals(name) || -+ "listIterator".equals(name); -+ } -+ -+ private static boolean isHasNextCall(Exprent exp) { -+ final InvocationExprent iexp = asInvocationExprent(exp); -+ if (iexp == null) { -+ return false; -+ } -+ if (!DecompilerContext.getStructContext().instanceOf(iexp.getClassName(), "java/util/Iterator")) { -+ return false; -+ } -+ return "hasNext".equals(iexp.getName()) && "()Z".equals(iexp.getStringDescriptor()); -+ } -+ -+ private static boolean isNextCall(Exprent exp) { -+ final InvocationExprent iexp = asInvocationExprent(exp); -+ if (iexp == null) { -+ return false; -+ } -+ if (!DecompilerContext.getStructContext().instanceOf(iexp.getClassName(), "java/util/Iterator")) { -+ return false; -+ } -+ return "next".equals(iexp.getName()) && "()Ljava/lang/Object;".equals(iexp.getStringDescriptor()); -+ } -+ -+ private static boolean isNextUnboxing(Exprent exprent) { -+ Exprent exp = getUncast(exprent); -+ if (exp.type != Exprent.EXPRENT_INVOCATION) -+ return false; -+ InvocationExprent inv = (InvocationExprent)exp; -+ return inv.isUnboxingCall() && isNextCall(inv.getInstance()); -+ } -+ -+ public static boolean makeDoWhileLoops(RootStatement root) { -+ if (makeDoWhileRec(root)) { -+ SequenceHelper.condenseSequences(root); -+ return true; -+ } -+ return false; -+ } -+ -+ private static boolean makeDoWhileRec(Statement stat) { -+ boolean ret = false; -+ -+ for (Statement st : stat.getStats()) { -+ ret |= makeDoWhileRec(st); -+ } -+ -+ if (stat.type == Statement.StatementType.DO) { -+ DoStatement dostat = (DoStatement)stat; -+ if (dostat.getLoopType() == DoStatement.LoopType.DO) { -+ matchDoWhile(dostat); -+ ret |= dostat.getLoopType() != DoStatement.LoopType.DO; -+ } -+ } -+ -+ return ret; -+ } -+ -+ private static boolean addContinueOrBreak(DoStatement stat, StatEdge ifedge) { -+ Statement outer = stat.getParent(); -+ while (outer != null && outer.type != Statement.StatementType.SWITCH && outer.type != Statement.StatementType.DO) { -+ outer = outer.getParent(); -+ } -+ -+ if (outer != null && (outer.type == Statement.StatementType.SWITCH || ((DoStatement)outer).getLoopType() != DoStatement.LoopType.DO)) { -+ Statement parent = stat.getParent(); -+ if (parent.type != Statement.StatementType.SEQUENCE || parent.getStats().getLast().equals(stat)) { -+ // need to insert a break or continue after the loop -+ if (ifedge.getDestination().equals(outer)) { -+ stat.addSuccessor(new StatEdge(StatEdge.EdgeType.CONTINUE, stat, ifedge.getDestination(), outer)); -+ return true; -+ } -+ else if (MergeHelper.isDirectPath(outer, ifedge.getDestination())) { -+ stat.addSuccessor(new StatEdge(StatEdge.EdgeType.BREAK, stat, ifedge.getDestination(), outer)); -+ return true; -+ } -+ } -+ } -+ -+ return false; -+ } -+} -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java -index 9d0ec7c864030386838efd4952da1e999ccd967e..81b4c480810a2f74388a4626a4dc0c2bfc523365 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java -@@ -5,19 +5,31 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; - import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph; - import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode; - import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper; - import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; - import org.jetbrains.java.decompiler.struct.gen.VarType; - -+import java.util.HashMap; - import java.util.HashSet; - import java.util.LinkedList; - import java.util.List; -+import java.util.Map; -+import java.util.Objects; - - public class PPandMMHelper { - - private boolean exprentReplaced; -+ private VarProcessor varProc; -+ private Map remaps = new HashMap<>(); -+ -+ public PPandMMHelper(VarProcessor varProc) { -+ this.varProc = varProc; -+ } - - public boolean findPPandMM(RootStatement root) { - -@@ -45,6 +57,8 @@ public class PPandMMHelper { - stack.addAll(node.successors); - } - -+ updateVersions(dgraph); -+ - return res; - } - -@@ -120,13 +134,18 @@ public class PPandMMHelper { - Exprent left = as.getLeft(); - - VarType condtype = econd.getExprType(); -- if (left.equals(econd) && (midlayer == null || midlayer.equals(condtype))) { -+ if (exprsEqual(left, econd) && (midlayer == null || midlayer.equals(condtype))) { - FunctionExprent ret = new FunctionExprent( - func.getFuncType() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI, - econd, func.bytecode); - ret.setImplicitType(condtype); - - exprentReplaced = true; -+ -+ if (!left.equals(econd)) { -+ remaps.put(new VarVersionPair((VarExprent)left), new VarVersionPair((VarExprent)econd)); -+ } -+ - return ret; - } - } -@@ -136,4 +155,48 @@ public class PPandMMHelper { - - return null; - } -+ -+ private boolean exprsEqual(Exprent e1, Exprent e2) { -+ if (e1 == e2) return true; -+ if (e1 == null || e2 == null) return false; -+ if (e1.type == Exprent.EXPRENT_VAR) { -+ return varsEqual(e1, e2); -+ } -+ return e1.equals(e2); -+ } -+ -+ private boolean varsEqual(Exprent e1, Exprent e2) { -+ if (!(e1 instanceof VarExprent)) return false; -+ if (!(e2 instanceof VarExprent)) return false; -+ -+ VarExprent v1 = (VarExprent)e1; -+ VarExprent v2 = (VarExprent)e2; -+ return varProc.getVarOriginalIndex(v1.getIndex()) == varProc.getVarOriginalIndex(v2.getIndex()) -+ && Objects.equals(v1.getVarType(), v2.getVarType()); -+ } -+ -+ -+ private void updateVersions(DirectGraph graph) { -+ if (remaps.isEmpty()) return; -+ graph.iterateExprents(new DirectGraph.ExprentIterator() { -+ @Override -+ public int processExprent(Exprent exprent) { -+ List lst = exprent.getAllExprents(true); -+ lst.add(exprent); -+ -+ for (Exprent expr : lst) { -+ if (expr.type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)expr; -+ VarVersionPair nvar = remaps.get(new VarVersionPair(var)); -+ if (nvar != null) { -+ var.setIndex(nvar.var); -+ var.setVersion(nvar.version); -+ } -+ } -+ } -+ -+ return 0; -+ } -+ }); -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java b/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java -index c3263800aba7cb93e7b879d0bd46888fb696e861..d7c81a5f8538cdb6c99c752a9dd0fba5cb767121 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java -@@ -15,6 +15,7 @@ public class StatEdge { - public Statement closure; - public boolean labeled = true; - public boolean explicit = true; -+ public boolean canInline = true; - - public StatEdge(@NotNull EdgeType type, Statement source, Statement destination, Statement closure) { - this(type, source, destination); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java -index a86f0d2887c6c19cb1d911ec43830eb69f8aaada..bce06b032577f4e6e5a891b06435fdd62ee5ea3f 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java -@@ -3,6 +3,7 @@ package org.jetbrains.java.decompiler.modules.decompiler.decompose; - - import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; - import org.jetbrains.java.decompiler.modules.decompiler.StatEdge.EdgeType; -+import org.jetbrains.java.decompiler.modules.decompiler.StrongConnectivityHelper; - import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; - import org.jetbrains.java.decompiler.util.FastFixedSetFactory; - import org.jetbrains.java.decompiler.util.FastFixedSetFactory.FastFixedSet; -@@ -51,6 +52,8 @@ public class FastExtendedPostdominanceHelper { - - filterOnDominance(filter); - -+ addSupportedComponents(filter); -+ - Set>> entries = mapExtPostdominators.entrySet(); - HashMap> res = new HashMap<>(entries.size()); - for (Entry> entry : entries) { -@@ -119,6 +122,23 @@ public class FastExtendedPostdominanceHelper { - } - } - -+ private void addSupportedComponents(DominatorTreeExceptionFilter filter) { -+ StrongConnectivityHelper schelp = new StrongConnectivityHelper(this.statement); -+ -+ for (List comp : schelp.getComponents()) { -+ SupportComponent supcomp = SupportComponent.identify(comp, this.mapSupportPoints, filter.getDomEngine()); -+ -+ if (supcomp != null) { -+ // If the identified support component is not null, then add additional postdom info -+ for (Statement st : supcomp.stats) { -+ if (st != supcomp.supportedPoint) { -+ this.mapExtPostdominators.computeIfAbsent(st.id, i -> this.factory.spawnEmptySet()).add(supcomp.supportedPoint.id); -+ } -+ } -+ } -+ } -+ } -+ - private void filterOnExceptionRanges(DominatorTreeExceptionFilter filter) { - for (Integer head : new HashSet<>(mapExtPostdominators.keySet())) { - FastFixedSet set = mapExtPostdominators.get(head); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/SupportComponent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/SupportComponent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9123d92be14259e0117a0bb7b06a3d09958f7459 ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/SupportComponent.java -@@ -0,0 +1,92 @@ -+package org.jetbrains.java.decompiler.modules.decompiler.decompose; -+ -+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; -+import org.jetbrains.java.decompiler.util.FastFixedSetFactory; -+ -+import java.util.*; -+ -+// Model of a strongly connected component, the entrypoint (header), and the backedges to the entrypoint. -+// This allows us to find endpoint cycles to better calculate postdominance -+public final class SupportComponent { -+ // Statements in this component -+ public final List stats; -+ // Backedges to loop header -+ public final Map> selfSupportPoints; -+ // Loop header -+ public final Statement supportedPoint; -+ -+ public SupportComponent(List stats, Map> selfSupportPoints, Statement supportedPoint) { -+ this.stats = stats; -+ this.selfSupportPoints = selfSupportPoints; -+ this.supportedPoint = supportedPoint; -+ } -+ -+ -+ public static SupportComponent identify(List component, Map> mapSupportPoints, DominatorEngine dom) { -+ Map> selfSupportPoints = new HashMap<>(); -+ Set supportedAll = new HashSet<>(); -+ for (Statement st : component) { -+ FastFixedSetFactory.FastFixedSet supReach = mapSupportPoints.get(st.id); -+ -+ if (supReach != null) { -+ for (StatEdge edge : st.getSuccessorEdges(StatEdge.EdgeType.REGULAR)) { -+ Statement dest = edge.getDestination(); -+ -+ if (!component.contains(dest)) { -+ // Support point supports statement outside of component, invalid -+ return null; -+ } else { -+ // If the successor is a dominator of the current statement, then we know that it must be an earlier statement, so the successor is supported point -+ if (dom.isDominator(st.id, dest.id)) { -+ supportedAll.add(dest); -+ } -+ } -+ } -+ -+ // no filter needed as this is coming from the component itself -+ selfSupportPoints.put(st.id, supReach); -+ } -+ } -+ -+ // There should only be a single component that is supported: if there's more, then we know that there is a nested loop -+ // TODO: The algorithm isn't able to decompose nested loops, so we simply quit processing for now -+ if (supportedAll.size() != 1) { -+ return null; -+ } -+ -+ // Somehow got no support points- should be impossible! -+ if (selfSupportPoints.isEmpty()) { -+ return null; -+ } -+ -+ // Find all edges leaving this component. There should only be one, and that is the edge leading into the header! -+ List outgoing = new ArrayList<>(); -+ for (Statement st : component) { -+ for (StatEdge edge : st.getPredecessorEdges(StatEdge.EdgeType.REGULAR)) { -+ if (!component.contains(edge.getSource())) { -+ outgoing.add(st); -+ } -+ } -+ } -+ -+ if (outgoing.size() != 1) { -+ return null; -+ } -+ -+ // Ensure that the header is the dominator of every node in the component -+ Statement head = outgoing.get(0); -+ for (Statement st : component) { -+ if (!dom.isDominator(st.id, head.id)) { -+ return null; -+ } -+ } -+ -+ return new SupportComponent(component, selfSupportPoints, head); -+ } -+ -+ @Override -+ public String toString() { -+ return "SupportComponent[" + stats + ", selfSupportPoints=" + selfSupportPoints + ", header=" + supportedPoint + ']'; -+ } -+} -\ 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 3cedf46af2faa91029231205455a1df1db7be3de..6776219b98b6b244bb9deda8cffc7b8fc63e4ac6 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -@@ -443,7 +443,7 @@ public class InvocationExprent extends Exprent { - "charValue", "java/lang/Character" - ); - -- private boolean isUnboxingCall() { -+ public boolean isUnboxingCall() { - return !isStatic && parameters.size() == 0 && className.equals(UNBOXING_METHODS.get(name)); - } - -@@ -643,4 +643,4 @@ public class InvocationExprent extends Exprent { - - return true; - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index 2b508a172340285dff5afa73cd4d7fcbf0dfeaff..8abfd33115391d24d08d349af9a5b64b1d75c1bf 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -@@ -9,11 +9,13 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.main.rels.MethodWrapper; - import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; --import org.jetbrains.java.decompiler.struct.StructMethod; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute; -+import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute.LocalVariable; - import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTypeTableAttribute; - import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor; -@@ -22,13 +24,13 @@ import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue; - import org.jetbrains.java.decompiler.util.TextBuffer; --import org.jetbrains.java.decompiler.util.TextUtil; - - import java.util.ArrayList; --import java.util.Collections; - import java.util.BitSet; -+import java.util.Collections; - import java.util.List; - import java.util.Objects; -+import java.util.stream.Collectors; - - public class VarExprent extends Exprent { - public static final int STACK_BASE = 10000; -@@ -41,6 +43,7 @@ public class VarExprent extends Exprent { - private int version = 0; - private boolean classDef = false; - private boolean stack = false; -+ private LocalVariable lvt = null; - - public VarExprent(int index, VarType varType, VarProcessor processor) { - this(index, varType, processor, null); -@@ -76,6 +79,7 @@ public class VarExprent extends Exprent { - var.setVersion(version); - var.setClassDef(classDef); - var.setStack(stack); -+ var.setLVT(lvt); - return var; - } - -@@ -92,10 +96,6 @@ public class VarExprent extends Exprent { - } - else { - VarVersionPair varVersion = getVarVersionPair(); -- String name = null; -- if (processor != null) { -- name = processor.getVarName(varVersion); -- } - - if (definition) { - if (processor != null && processor.getVarFinal(varVersion) == VarProcessor.VAR_EXPLICIT_FINAL) { -@@ -105,7 +105,7 @@ public class VarExprent extends Exprent { - buffer.append(" "); - } - -- buffer.append(name == null ? ("var" + index + (this.version == 0 ? "" : "_" + this.version)) : name); -+ buffer.append(getName()); - } - - return buffer; -@@ -115,6 +115,7 @@ public class VarExprent extends Exprent { - return new VarVersionPair(index, version); - } - -+ /* - public String getDebugName(StructMethod method) { - StructLocalVariableTableAttribute attr = method.getLocalVariableAttr(); - if (attr != null && processor != null) { -@@ -128,9 +129,25 @@ public class VarExprent extends Exprent { - } - return null; - } -+ */ - - private void appendDefinitionType(TextBuffer buffer) { - if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) { -+ -+ if (lvt != null) { -+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -+ if (lvt.getSignature() != null) { -+ GenericFieldDescriptor descriptor = GenericMain.parseFieldSignature(lvt.getSignature()); -+ if (descriptor != null) { -+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.type, Collections.emptyList())); -+ return; -+ } -+ } -+ } -+ buffer.append(ExprProcessor.getCastTypeName(getVarType(), Collections.emptyList())); -+ return; -+ } -+ - MethodWrapper method = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); - if (method != null) { - Integer originalIndex = null; -@@ -195,6 +212,10 @@ public class VarExprent extends Exprent { - } - - public VarType getVarType() { -+ if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES) && lvt != null) { -+ return new VarType(lvt.getDescriptor()); -+ } -+ - VarType vt = null; - if (processor != null) { - vt = processor.getVarType(getVarVersionPair()); -@@ -247,6 +268,93 @@ public class VarExprent extends Exprent { - this.stack = stack; - } - -+ public void setLVT(LocalVariable var) { -+ this.lvt = var; -+ if (processor != null && lvt != null) { -+ processor.setVarType(getVarVersionPair(), lvt.getVarType()); -+ } -+ } -+ -+ public LocalVariable getLVT() { -+ return lvt; -+ } -+ -+ public String getName() { -+ VarVersionPair pair = getVarVersionPair(); -+ if (lvt != null) -+ return lvt.getName(); -+ -+ if (processor != null) { -+ String ret = processor.getVarName(pair); -+ if (ret != null) -+ return ret; -+ } -+ -+ return pair.version == 0 ? "var" + pair.var : "var" + pair.var + "_" + version; -+ } -+ -+ @Override -+ public CheckTypesResult checkExprTypeBounds() { -+ if (lvt != null) { -+ CheckTypesResult ret = new CheckTypesResult(); -+ ret.addMinTypeExprent(this, lvt.getVarType()); -+ return ret; -+ } -+ return null; -+ } -+ -+ public boolean isVarReferenced(Statement stat, VarExprent... whitelist) { -+ if (stat.getExprents() == null) { -+ for (Object obj : stat.getSequentialObjects()) { -+ if (obj instanceof Statement) { -+ if (isVarReferenced((Statement)obj, whitelist)) { -+ return true; -+ } -+ } -+ else if (obj instanceof Exprent) { -+ if (isVarReferenced((Exprent)obj, whitelist)) { -+ return true; -+ } -+ } -+ } -+ } -+ else { -+ for (Exprent exp : stat.getExprents()) { -+ if (isVarReferenced(exp, whitelist)) { -+ return true; -+ } -+ } -+ } -+ return false; -+ } -+ -+ public boolean isVarReferenced(Exprent exp, VarExprent... whitelist) { -+ List lst = exp.getAllExprents(true); -+ lst.add(exp); -+ lst = lst.stream().filter(e -> e != this && e.type == Exprent.EXPRENT_VAR && -+ getVarVersionPair().equals(((VarExprent)e).getVarVersionPair())) -+ .collect(Collectors.toList()); -+ -+ for (Exprent var : lst) { -+ boolean allowed = false; -+ for (VarExprent white : whitelist) { -+ if (var == white) { -+ allowed = true; -+ break; -+ } -+ } -+ if (!allowed) { -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ @Override -+ public String toString() { -+ return "VarExprent[" + index + ',' + version +"]"; -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java -index a20acdff7d3ef1415fe6c90d05b92a90cfaf0073..6f21cd6df597613099861d874bb320effd0a366a 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java -@@ -113,6 +113,21 @@ public class DirectGraph { - return true; - } - -+ public boolean iterateExprentsDeep(ExprentIterator itr) { -+ return iterateExprents(exprent -> { -+ List lst = exprent.getAllExprents(true); -+ lst.add(exprent); -+ -+ for (Exprent expr : lst) { -+ int res = itr.processExprent(expr); -+ if (res == 1 || res == 2) { -+ return res; -+ } -+ } -+ return 0; -+ }); -+ } -+ - public interface ExprentIterator { - // 0 - success, do nothing - // 1 - cancel iteration -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java -index 552ae9594a64c737095bc5ec095e134926c1315c..234a42e3a73426204cf3debdb9b77c28f4afbb10 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java -@@ -201,7 +201,7 @@ public class FlattenStatementsHelper { - } - sourcenode = node; - } -- case FOR -> { -+ case FOR, FOREACH -> { - DirectNode nodeinit = new DirectNode(DirectNodeType.INIT, stat, stat.id + "_init"); - if (dostat.getInitExprent() != null) { - nodeinit.exprents = dostat.getInitExprentList(); -@@ -209,7 +209,9 @@ public class FlattenStatementsHelper { - graph.nodes.putWithKey(nodeinit, nodeinit.id); - - DirectNode nodecond = new DirectNode(DirectNodeType.CONDITION, stat, stat.id + "_cond"); -- nodecond.exprents = dostat.getConditionExprentList(); -+ if (loopType != DoStatement.LoopType.FOREACH) { -+ nodecond.exprents = dostat.getConditionExprentList(); -+ } - graph.nodes.putWithKey(nodecond, nodecond.id); - - DirectNode nodeinc = new DirectNode(DirectNodeType.INCREMENT, stat, stat.id + "_inc"); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java -index 56f429ac8433cd5db3e5ea22ab4c3b0e8c7927f5..018d3fbdf53036db90b6c64e872098542133b630 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java -@@ -105,6 +105,14 @@ public final class DoStatement extends Statement { - buf.appendIndent(indent).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - } -+ case FOREACH -> { -+ buf.appendIndent(indent).append("for(").append(initExprent.get(0).toJava(indent, tracer)); -+ buf.append(" : ").append(incExprent.get(0).toJava(indent, tracer)).append(") {").appendLineSeparator(); -+ tracer.incrementCurrentSourceLine(); -+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); -+ buf.appendIndent(indent).append("}").appendLineSeparator(); -+ tracer.incrementCurrentSourceLine(); -+ } - } - return buf; - } -@@ -119,6 +127,10 @@ public final class DoStatement extends Statement { - } - case WHILE: - lst.add(getConditionExprent()); -+ break; -+ case FOREACH: -+ lst.add(getInitExprent()); -+ lst.add(getIncExprent()); - } - lst.add(first); - switch (loopType) { -@@ -194,6 +206,7 @@ public final class DoStatement extends Statement { - DO, - DO_WHILE, - WHILE, -- FOR -+ FOR, -+ FOREACH - } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -index 9498f3c548d18ead3bcbc076222bd5ace82b8275..e65af740228e237d3159cf4dd3398a9fe1d21199 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java -@@ -768,6 +768,14 @@ public abstract class Statement implements IMatchable { - this.parent = parent; - } - -+ public Statement getTopParent() { -+ Statement ret = this; -+ while (ret.getParent() != null) { -+ ret = ret.getParent(); -+ } -+ return ret; -+ } -+ - public HashSet getLabelEdges() { // FIXME: why HashSet? - return labelEdges; - } -@@ -794,7 +802,7 @@ public abstract class Statement implements IMatchable { - - // helper methods - public String toString() { -- return Integer.toString(id); -+ return String.format("{%d}:%d", type, id); - } - - //TODO: Cleanup/cache? -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -index 0113b76b89a886a96d8f1668142b008cb85ab637..f2c0589344ed69685dd3103d060109c700c7ee41 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -@@ -4,18 +4,28 @@ package org.jetbrains.java.decompiler.modules.decompiler.vars; - import org.jetbrains.java.decompiler.code.CodeConstants; - import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector; -+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; - import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement; - import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement; - import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement; - import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement.LoopType; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement; - import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; - import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement.StatementType; - import org.jetbrains.java.decompiler.struct.StructClass; - import org.jetbrains.java.decompiler.struct.StructMethod; -+import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute.LocalVariable; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; - - import java.util.*; - import java.util.Map.Entry; -@@ -31,6 +41,9 @@ public class VarDefinitionHelper { - - private final VarProcessor varproc; - -+ private final Statement root; -+ private final StructMethod mt; -+ - public VarDefinitionHelper(Statement root, StructMethod mt, VarProcessor varproc) { - - mapVarDefStatements = new HashMap<>(); -@@ -38,6 +51,8 @@ public class VarDefinitionHelper { - implDefVars = new HashSet<>(); - - this.varproc = varproc; -+ this.root = root; -+ this.mt = mt; - - VarNamesCollector vc = varproc.getVarNamesCollector(); - -@@ -51,12 +66,12 @@ public class VarDefinitionHelper { - } - paramcount += md.params.length; - -- - // method parameters are implicitly defined - int varindex = 0; - for (int i = 0; i < paramcount; i++) { - implDefVars.add(varindex); -- varproc.setVarName(new VarVersionPair(varindex, 0), vc.getFreeName(varindex)); -+ VarVersionPair vpp = new VarVersionPair(varindex, 0); -+ varproc.setVarName(vpp, vc.getFreeName(varindex)); - - if (thisvar) { - if (i == 0) { -@@ -79,6 +94,8 @@ public class VarDefinitionHelper { - vc.addName("this"); - } - -+ mergeVars(root); -+ - // catch variables are implicitly defined - LinkedList stack = new LinkedList<>(); - stack.add(root); -@@ -108,7 +125,6 @@ public class VarDefinitionHelper { - initStatement(root); - } - -- - public void setVarDefinitions() { - VarNamesCollector vc = varproc.getVarNamesCollector(); - -@@ -141,9 +157,17 @@ public class VarDefinitionHelper { - } - } - } -+ else if (dstat.getLoopType() == DoStatement.LoopType.FOREACH) { -+ if (dstat.getInitExprent() != null && dstat.getInitExprent().type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)dstat.getInitExprent(); -+ if (var.getIndex() == index.intValue()) { -+ var.setDefinition(true); -+ continue; -+ } -+ } -+ } - } - -- - Statement first = findFirstBlock(stat, index); - - List lst; -@@ -157,7 +181,6 @@ public class VarDefinitionHelper { - lst = first.getExprents(); - } - -- - boolean defset = false; - - // search for the first assignment to var [index] -@@ -186,9 +209,17 @@ public class VarDefinitionHelper { - VarExprent var = new VarExprent(index, varproc.getVarType(new VarVersionPair(index.intValue(), 0)), varproc); - var.setDefinition(true); - -+ LocalVariable lvt = findLVT(index.intValue(), stat); -+ if (lvt != null) { -+ var.setLVT(lvt); -+ } -+ - lst.add(addindex, var); - } - } -+ -+ mergeVars(root); -+ propogateLVTs(root); - } - - -@@ -196,6 +227,50 @@ public class VarDefinitionHelper { - // private methods - // ***************************************************************************** - -+ private LocalVariable findLVT(int index, Statement stat) { -+ if (stat.getExprents() == null) { -+ for (Object obj : stat.getSequentialObjects()) { -+ if (obj instanceof Statement) { -+ LocalVariable lvt = findLVT(index, (Statement)obj); -+ if (lvt != null) { -+ return lvt; -+ } -+ } -+ else if (obj instanceof Exprent) { -+ LocalVariable lvt = findLVT(index, (Exprent)obj); -+ if (lvt != null) { -+ return lvt; -+ } -+ } -+ } -+ } -+ else { -+ for (Exprent exp : stat.getExprents()) { -+ LocalVariable lvt = findLVT(index, exp); -+ if (lvt != null) { -+ return lvt; -+ } -+ } -+ } -+ return null; -+ } -+ -+ private LocalVariable findLVT(int index, Exprent exp) { -+ for (Exprent e: exp.getAllExprents(false)) { -+ LocalVariable lvt = findLVT(index, e); -+ if (lvt != null) { -+ return lvt; -+ } -+ } -+ -+ if (exp.type != Exprent.EXPRENT_VAR) { -+ return null; -+ } -+ -+ VarExprent var = (VarExprent)exp; -+ return var.getIndex() == index ? var.getLVT() : null; -+ } -+ - private Statement findFirstBlock(Statement stat, Integer varindex) { - - LinkedList stack = new LinkedList<>(); -@@ -249,6 +324,7 @@ public class VarDefinitionHelper { - if (st.type == StatementType.DO) { - DoStatement dost = (DoStatement)st; - if (dost.getLoopType() != LoopType.FOR && -+ dost.getLoopType() != LoopType.FOREACH && - dost.getLoopType() != LoopType.DO) { - currVars.add(dost.getConditionExprent()); - } -@@ -319,7 +395,7 @@ public class VarDefinitionHelper { - return res; - } - -- private static boolean setDefinition(Exprent expr, Integer index) { -+ private boolean setDefinition(Exprent expr, Integer index) { - if (expr.type == Exprent.EXPRENT_ASSIGNMENT) { - Exprent left = ((AssignmentExprent)expr).getLeft(); - if (left.type == Exprent.EXPRENT_VAR) { -@@ -332,4 +408,660 @@ public class VarDefinitionHelper { - } - return false; - } -+ -+ private void populateTypeBounds(VarProcessor proc, Statement stat) { -+ Map mapExprentMinTypes = varproc.getVarVersions().getTypeProcessor().getMinExprentTypes(); -+ Map mapExprentMaxTypes = varproc.getVarVersions().getTypeProcessor().getMaxExprentTypes(); -+ LinkedList stack = new LinkedList<>(); -+ stack.add(root); -+ -+ while (!stack.isEmpty()) { -+ Statement st = stack.removeFirst(); -+ -+ if (st.getExprents() != null) { -+ LinkedList exps = new LinkedList<>(); -+ exps.addAll(st.getExprents()); -+ while (!exps.isEmpty()) { -+ Exprent exp = exps.removeFirst(); -+ -+ switch (exp.type) { -+ case Exprent.EXPRENT_INVOCATION: -+ case Exprent.EXPRENT_FIELD: -+ case Exprent.EXPRENT_EXIT: -+ Exprent instance = null; -+ String target = null; -+ if (exp.type == Exprent.EXPRENT_INVOCATION) { -+ instance = ((InvocationExprent)exp).getInstance(); -+ target = ((InvocationExprent)exp).getClassName(); -+ } else if (exp.type == Exprent.EXPRENT_FIELD) { -+ instance = ((FieldExprent)exp).getInstance(); -+ target = ((FieldExprent)exp).getClassname(); -+ } else if (exp.type == Exprent.EXPRENT_EXIT) { -+ ExitExprent exit = (ExitExprent)exp; -+ if (exit.getExitType() == ExitExprent.EXIT_RETURN) { -+ instance = exit.getValue(); -+ target = exit.getRetType().getValue(); -+ } -+ } -+ -+ if ("java/lang/Object".equals(target)) -+ continue; //This is dirty, but if we don't then too many things become object... -+ -+ if (instance != null && instance.type == Exprent.EXPRENT_VAR) { -+ VarVersionPair key = ((VarExprent)instance).getVarVersionPair(); -+ VarType newType = new VarType(CodeConstants.TYPE_OBJECT, 0, target); -+ VarType oldMin = mapExprentMinTypes.get(key); -+ VarType oldMax = mapExprentMaxTypes.get(key); -+ -+ /* Everything goes to Object with this... Need a better filter? -+ if (!newType.equals(oldMin)) { -+ if (oldMin != null && oldMin.type == CodeConstants.TYPE_OBJECT) { -+ // If the old min is an instanceof the new target, EXA: ArrayList -> List -+ if (DecompilerContext.getStructContext().instanceOf(oldMin.value, newType.value)) -+ mapExprentMinTypes.put(key, newType); -+ } else -+ mapExprentMinTypes.put(key, newType); -+ } -+ */ -+ -+ if (!newType.equals(oldMax)) { -+ if (oldMax != null && oldMax.getType() == CodeConstants.TYPE_OBJECT) { -+ // If the old min is an instanceof the new target, EXA: List -> ArrayList -+ if (DecompilerContext.getStructContext().instanceOf(newType.getValue(), oldMax.getValue())) -+ mapExprentMaxTypes.put(key, newType); -+ } else -+ mapExprentMaxTypes.put(key, newType); -+ } -+ } -+ -+ break; -+ default: -+ exps.addAll(exp.getAllExprents()); -+ } -+ } -+ } -+ -+ stack.addAll(st.getStats()); -+ } -+ } -+ -+ private VPPEntry mergeVars(Statement stat) { -+ Map parent = new HashMap<>(); // Always empty dua! -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); -+ -+ int index = 0; -+ if (!mt.hasModifier(CodeConstants.ACC_STATIC)) { -+ parent.put(index, new VarVersionPair(index++, 0)); -+ } -+ -+ for (VarType var : md.params) { -+ parent.put(index, new VarVersionPair(index, 0)); -+ index += var.getStackSize(); -+ } -+ -+ populateTypeBounds(varproc, stat); -+ -+ Map blacklist = new HashMap<>(); -+ VPPEntry remap = mergeVars(stat, parent, new HashMap(), blacklist); -+ while (remap != null) { -+ //System.out.println("Remapping: " + remap.getKey() + " -> " + remap.getValue()); -+ if (!remapVar(stat, remap.getKey(), remap.getValue())) { -+ blacklist.put(remap.getKey(), remap.getValue()); -+ } -+ remap = mergeVars(stat, parent, new HashMap(), blacklist); -+ } -+ return null; -+ } -+ -+ -+ private VPPEntry mergeVars(Statement stat, Map parent, Map leaked, Map blacklist) { -+ Map this_vars = new HashMap<>(); -+ if (parent.size() > 0) -+ this_vars.putAll(parent); -+ -+ if (stat.getVarDefinitions().size() > 0) { -+ 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 VarVersionPair(var)); -+ leaked.put(index, new VarVersionPair(var)); -+ } -+ } -+ } -+ -+ Map scoped = null; -+ switch (stat.type) { // These are the type of statements that leak vars -+ case BASIC_BLOCK: -+ case GENERAL: -+ case ROOT: -+ case SEQUENCE: -+ scoped = leaked; -+ } -+ -+ if (stat.getExprents() == null) { -+ List objs = stat.getSequentialObjects(); -+ for (int i = 0; i < objs.size(); i++) { -+ Object obj = objs.get(i); -+ if (obj instanceof Statement) { -+ Statement st = (Statement)obj; -+ -+ //Map blacklist_n = new HashMap(); -+ Map 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.size() > 0) { -+ 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 mwhahahahah! -+ } -+ this_vars.putAll(leaked_n); -+ } -+ } -+ else if (obj instanceof Exprent) { -+ VPPEntry ret = processExprent((Exprent)obj, this_vars, scoped, blacklist); -+ if (ret != null && isVarReadFirst(ret.getValue(), stat, i + 1)) { -+ return ret; -+ } -+ } -+ } -+ } -+ else { -+ List 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!!!!!!! -+ } -+ -+ private VPPEntry processExprent(Exprent exp, Map this_vars, Map leaked, Map blacklist) { -+ VarExprent var = null; -+ -+ if (exp.type == Exprent.EXPRENT_ASSIGNMENT) { -+ AssignmentExprent ass = (AssignmentExprent)exp; -+ if (ass.getLeft().type != Exprent.EXPRENT_VAR) { -+ return null; -+ } -+ -+ var = (VarExprent)ass.getLeft(); -+ } -+ else if (exp.type == Exprent.EXPRENT_VAR) { -+ var = (VarExprent)exp; -+ } -+ -+ if (var == null) { -+ return null; -+ } -+ -+ if (!var.isDefinition()) { -+ return null; -+ } -+ -+ int index = varproc.getVarOriginalIndex(var.getIndex()); -+ VarVersionPair new_ = this_vars.get(index); -+ if (new_ != null) { -+ VarVersionPair old = new VarVersionPair(var); -+ VarVersionPair black = blacklist.get(old); -+ if (black == null || !black.equals(new_)) { -+ return new VPPEntry(var, this_vars.get(index)); -+ } -+ } -+ this_vars.put(index, new VarVersionPair(var)); -+ -+ if (leaked != null) { -+ leaked.put(index, new VarVersionPair(var)); -+ } -+ -+ return null; -+ } -+ -+ private boolean remapVar(Statement stat, VarVersionPair from, VarVersionPair to) { -+ if (from.equals(to)) -+ throw new IllegalArgumentException("Shit went wrong: " + from); -+ boolean success = false; -+ if (stat.getExprents() == null) { -+ for (Object obj : stat.getSequentialObjects()) { -+ if (obj instanceof Statement) { -+ success |= remapVar((Statement)obj, from, to); -+ } -+ else if (obj instanceof Exprent) { -+ if (remapVar((Exprent)obj, from, to)) { -+ success = true; -+ } -+ } -+ } -+ } -+ else { -+ boolean remapped = false; -+ for (int x = 0; x < stat.getExprents().size(); x++) { -+ Exprent exp = stat.getExprents().get(x); -+ if (remapVar(exp, from, to)) { -+ remapped = true; -+ if (exp.type == Exprent.EXPRENT_VAR) { -+ if (!((VarExprent)exp).isDefinition()) { -+ stat.getExprents().remove(x); -+ x--; -+ } -+ } -+ } -+ } -+ success |= remapped; -+ } -+ -+ if (success) { -+ Iterator itr = stat.getVarDefinitions().iterator(); -+ while (itr.hasNext()) { -+ Exprent exp = itr.next(); -+ if (exp.type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)exp; -+ if (from.equals(var.getVarVersionPair())) { -+ itr.remove(); -+ } -+ else if (to.var == var.getIndex() && to.version == var.getVersion()) { -+ VarType merged = getMergedType(from, to); -+ -+ if (merged == null) { // Something went wrong.. This SHOULD be non-null -+ continue; -+ } -+ -+ var.setVarType(merged); -+ } -+ } -+ } -+ } -+ -+ return success; -+ } -+ -+ private boolean remapVar(Exprent exprent, VarVersionPair from, VarVersionPair to) { -+ if (exprent == null) { // Sometimes there are null exprents? -+ return false; -+ } -+ List lst = exprent.getAllExprents(true); -+ lst.add(exprent); -+ -+ boolean remapped = false; -+ -+ for (Exprent expr : lst) { -+ if (expr.type == Exprent.EXPRENT_ASSIGNMENT) { -+ AssignmentExprent ass = (AssignmentExprent)expr; -+ if (ass.getLeft().type == Exprent.EXPRENT_VAR && ass.getRight().type == Exprent.EXPRENT_CONST) { -+ VarVersionPair left = new VarVersionPair((VarExprent)ass.getLeft()); -+ if (!left.equals(from) && !left.equals(to)) { -+ continue; -+ } -+ -+ ConstExprent right = (ConstExprent)ass.getRight(); -+ if (right.getConstType() == VarType.VARTYPE_NULL) { -+ continue; -+ } -+ VarType merged = getMergedType(from, to); -+ if (merged == null) { // Types incompatible, do not merge -+ continue; -+ } -+ -+ right.setConstType(merged); -+ } -+ } -+ else if (expr.type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)expr; -+ VarVersionPair old = new VarVersionPair(var); -+ if (!old.equals(from)) { -+ continue; -+ } -+ VarType merged = getMergedType(from, to); -+ if (merged == null) { // Types incompatible, do not merge -+ continue; -+ } -+ -+ var.setIndex(to.var); -+ var.setVersion(to.version); -+ var.setVarType(merged); -+ if (var.isDefinition()) { -+ var.setDefinition(false); -+ } -+ varproc.setVarType(to, merged); -+ remapped = true; -+ } -+ } -+ return remapped; -+ } -+ -+ private VarType getMergedType(VarVersionPair from, VarVersionPair to) { -+ Map minTypes = varproc.getVarVersions().getTypeProcessor().getMinExprentTypes(); -+ Map maxTypes = varproc.getVarVersions().getTypeProcessor().getMaxExprentTypes(); -+ return getMergedType(minTypes.get(from), minTypes.get(to), maxTypes.get(from), maxTypes.get(to)); -+ } -+ -+ private VarType getMergedType(VarType fromMin, VarType toMin, VarType fromMax, VarType toMax) { -+ if (fromMin != null && fromMin.equals(toMin)) { -+ return fromMin; // Short circuit this for simplicities sake -+ } -+ VarType type = fromMin == null ? toMin : (toMin == null ? fromMin : VarType.getCommonSupertype(fromMin, toMin)); -+ if (type == null || fromMin == null || toMin == null) { -+ return null; // no common supertype, skip the remapping -+ } -+ if (type.getType() == CodeConstants.TYPE_OBJECT) { -+ if (toMax != null) { // The target var is used in direct invocations -+ if (fromMax != null) { -+ // Max types are the highest class that this variable is used as a direct instance of without any casts. -+ // This will pull up the to var type if the from requires a higher class type. -+ // EXA: Collection -> List -+ if (DecompilerContext.getStructContext().instanceOf(fromMax.getValue(), toMax.getValue())) -+ return fromMax; -+ } else if (fromMin != null) { -+ // Pull to up to from: List -> ArrayList -+ if (DecompilerContext.getStructContext().instanceOf(fromMin.getValue(), toMax.getValue())) -+ return fromMin; -+ } -+ } else if (toMin != null) { -+ if (fromMax != null) { -+ if (DecompilerContext.getStructContext().instanceOf(fromMax.getValue(), toMin.getValue())) -+ return fromMax; -+ } else if (fromMin != null) { -+ if (DecompilerContext.getStructContext().instanceOf(toMin.getValue(), fromMin.getValue())) -+ return toMin; -+ } -+ } -+ return null; -+ } else { -+ return type; -+ } -+ } -+ -+ private void propogateLVTs(Statement stat) { -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); -+ Map types = new LinkedHashMap<>(); -+ -+ if (varproc.hasLVT()) { -+ int index = 0; -+ if (!mt.hasModifier(CodeConstants.ACC_STATIC)) { -+ List lvt = varproc.getCandidates(index); // Some enums give incomplete lvts? -+ if (lvt != null && lvt.size() > 0) { -+ types.put(new VarVersionPair(index, 0), new VarInfo(lvt.get(0), null)); -+ } -+ index++; -+ } -+ -+ for (VarType var : md.params) { -+ List lvt = varproc.getCandidates(index); // Some enums give incomplete lvts? -+ if (lvt != null && lvt.size() > 0) { -+ types.put(new VarVersionPair(index, 0), new VarInfo(lvt.get(0), null)); -+ } -+ index += var.getStackSize(); -+ } -+ } -+ -+ findTypes(stat, types); -+ -+ Map typeNames = new LinkedHashMap<>(); -+ for (Entry e : types.entrySet()) { -+ typeNames.put(e.getKey(), e.getValue().getCast()); -+ } -+ Map lvts = new HashMap<>(); -+ -+ for (Entry e : types.entrySet()) { -+ VarVersionPair idx = e.getKey(); -+ // skip this. we can't rename it -+ if (idx.var == 0 && !mt.hasModifier(CodeConstants.ACC_STATIC)) { -+ continue; -+ } -+ LocalVariable lvt = e.getValue().getLVT(); -+ if (lvt != null) { -+ varproc.setVarLVT(idx, lvt); -+ lvts.put(idx, lvt); -+ } -+ } -+ -+ -+ applyTypes(stat, lvts); -+ } -+ -+ private void findTypes(Statement stat, Map types) { -+ if (stat == null) { -+ return; -+ } -+ -+ for (Exprent exp : stat.getVarDefinitions()) { -+ findTypes(exp, types); -+ } -+ -+ if (stat.getExprents() == null) { -+ for (Object obj : stat.getSequentialObjects()) { -+ if (obj instanceof Statement) { -+ findTypes((Statement)obj, types); -+ } -+ else if (obj instanceof Exprent) { -+ findTypes((Exprent)obj, types); -+ } -+ } -+ } -+ else { -+ for (Exprent exp : stat.getExprents()) { -+ findTypes(exp, types); -+ } -+ } -+ } -+ -+ private void findTypes(Exprent exp, Map types) { -+ List lst = exp.getAllExprents(true); -+ lst.add(exp); -+ -+ for (Exprent exprent : lst) { -+ if (exprent.type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)exprent; -+ VarVersionPair ver = new VarVersionPair(var); -+ if (var.isDefinition()) { -+ types.put(ver, new VarInfo(var.getLVT(), var.getVarType())); -+ } else { -+ VarInfo existing = types.get(ver); -+ if (existing == null) -+ existing = new VarInfo(var.getLVT(), var.getVarType()); -+ else if (existing.getLVT() == null && var.getLVT() != null) -+ existing = new VarInfo(var.getLVT(), existing.getType()); -+ types.put(ver, existing); -+ } -+ } -+ } -+ } -+ -+ private void applyTypes(Statement stat, Map types) { -+ if (stat == null || types.size() == 0) { -+ return; -+ } -+ -+ for (Exprent exp : stat.getVarDefinitions()) { -+ applyTypes(exp, types); -+ } -+ -+ if (stat.getExprents() == null) { -+ for (Object obj : stat.getSequentialObjects()) { -+ if (obj instanceof Statement) { -+ applyTypes((Statement)obj, types); -+ } -+ else if (obj instanceof Exprent) { -+ applyTypes((Exprent)obj, types); -+ } -+ } -+ } -+ else { -+ for (Exprent exp : stat.getExprents()) { -+ applyTypes(exp, types); -+ } -+ } -+ } -+ -+ private void applyTypes(Exprent exprent, Map types) { -+ if (exprent == null) { -+ return; -+ } -+ List lst = exprent.getAllExprents(true); -+ lst.add(exprent); -+ -+ for (Exprent expr : lst) { -+ if (expr.type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)expr; -+ LocalVariable lvt = types.get(new VarVersionPair(var)); -+ if (lvt != null) { -+ var.setLVT(lvt); -+ } else { -+ System.currentTimeMillis(); -+ } -+ } -+ } -+ } -+ -+ //Helper classes because Java is dumb and doesn't have a Pair class -+ private static class SimpleEntry implements Entry { -+ private K key; -+ private V value; -+ public SimpleEntry(K key, V value) { -+ this.key = key; -+ this.value = value; -+ } -+ @Override public K getKey() { return key; } -+ @Override public V getValue() { return value; } -+ @Override -+ public V setValue(V value) { -+ V tmp = this.value; -+ this.value = value; -+ return tmp; -+ } -+ } -+ private static class VPPEntry extends SimpleEntry { -+ public VPPEntry(VarExprent key, VarVersionPair value) { -+ super(new VarVersionPair(key), value); -+ } -+ } -+ -+ private static class VarInfo { -+ private LocalVariable lvt; -+ private String cast; -+ private VarType type; -+ -+ private VarInfo(LocalVariable lvt, VarType type) { -+ if (lvt != null && lvt.getSignature() != null) -+ this.cast = GenericMain.getGenericCastTypeName(new GenericType(lvt.getSignature()), Collections.emptyList()); -+ else if (lvt != null) -+ this.cast = ExprProcessor.getCastTypeName(lvt.getVarType(), false, Collections.emptyList()); -+ else if (type != null) -+ this.cast = ExprProcessor.getCastTypeName(type, false, Collections.emptyList()); -+ else -+ this.cast = "this"; -+ this.lvt = lvt; -+ this.type = type; -+ } -+ -+ public LocalVariable getLVT() { -+ return this.lvt; -+ } -+ -+ public String getCast() { -+ return this.cast; -+ } -+ -+ public VarType getType() { -+ return this.type; -+ } -+ } -+ -+ private static boolean isVarReadFirst(VarVersionPair var, Statement stat, int index, VarExprent... whitelist) { -+ if (stat.getExprents() == null) { -+ List objs = stat.getSequentialObjects(); -+ for (int x = index; x < objs.size(); x++) { -+ Object obj = objs.get(x); -+ if (obj instanceof Statement) { -+ if (isVarReadFirst(var, (Statement)obj, 0, whitelist)) { -+ return true; -+ } -+ } -+ else if (obj instanceof Exprent) { -+ if (isVarReadFirst(var, (Exprent)obj, whitelist)) { -+ return true; -+ } -+ } -+ } -+ } -+ else { -+ for (int x = index; x < stat.getExprents().size(); x++) { -+ if (isVarReadFirst(var, stat.getExprents().get(x), whitelist)) { -+ return true; -+ } -+ } -+ } -+ return false; -+ } -+ -+ private static boolean isVarReadFirst(VarVersionPair target, Exprent exp, VarExprent... whitelist) { -+ AssignmentExprent ass = exp.type == Exprent.EXPRENT_ASSIGNMENT ? (AssignmentExprent)exp : null; -+ List lst = exp.getAllExprents(true); -+ lst.add(exp); -+ for (Exprent ex : lst) { -+ if (ex.type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)ex; -+ if (var.getIndex() == target.var && var.getVersion() == target.version) { -+ boolean allowed = false; -+ if (ass != null) { -+ if (var == ass.getLeft()) { -+ allowed = true; -+ } -+ } -+ for (VarExprent white : whitelist) { -+ if (var == white) { -+ allowed = true; -+ } -+ } -+ if (!allowed) { -+ return true; -+ } -+ } -+ } -+ } -+ return false; -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java -index 33c4c3efcf7d9b26737717a2445bffad0db5c4c0..559c96b54667b5b9a051039fdbb3643f8c8601b5 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java -@@ -5,16 +5,20 @@ import org.jetbrains.java.decompiler.code.CodeConstants; - import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector; - import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; - import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; - import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; - import org.jetbrains.java.decompiler.struct.StructClass; - import org.jetbrains.java.decompiler.struct.StructMethod; -+import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute.LocalVariable; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.util.StartEndPair; - import org.jetbrains.java.decompiler.util.TextUtil; - - import java.util.*; - import java.util.Map.Entry; -+import java.util.stream.Collectors; - - public class VarProcessor { - public static final int VAR_NON_FINAL = 1; -@@ -25,6 +29,7 @@ public class VarProcessor { - private final StructMethod method; - private final MethodDescriptor methodDescriptor; - private Map mapVarNames = new HashMap<>(); -+ private Map mapVarLVTs = new HashMap<>(); - private VarVersionsProcessor varVersions; - private final Map thisVars = new HashMap<>(); - private final Set externalVars = new HashSet<>(); -@@ -52,12 +57,12 @@ public class VarProcessor { - new VarDefinitionHelper(root, method, this).setVarDefinitions(); - } - -- public void setDebugVarNames(Map mapDebugVarNames) { -+ public void setDebugVarNames(Map mapDebugVarNames) { - if (varVersions == null) { - return; - } - -- Map mapOriginalVarIndices = varVersions.getMapOriginalVarIndices(); -+ Map mapOriginalVarIndices = varVersions.getMapOriginalVarIndices(); - - List listVars = new ArrayList<>(mapVarNames.keySet()); - listVars.sort(Comparator.comparingInt(o -> o.var)); -@@ -67,18 +72,20 @@ public class VarProcessor { - for (VarVersionPair pair : listVars) { - String name = mapVarNames.get(pair); - -- Integer index = mapOriginalVarIndices.get(pair.var); -- if (index != null) { -- String debugName = mapDebugVarNames.get(index); -+ boolean lvtName = false; -+ VarVersionPair key = mapOriginalVarIndices.get(pair.var); -+ if (key != null) { -+ String debugName = mapDebugVarNames.get(key); - if (debugName != null && TextUtil.isValidIdentifier(debugName, method.getBytecodeVersion())) { - name = debugName; -+ lvtName = true; - } - } - - Integer counter = mapNames.get(name); - mapNames.put(name, counter == null ? counter = 0 : ++counter); - -- if (counter > 0) { -+ if (counter > 0 && !lvtName) { - name += String.valueOf(counter); - } - -@@ -87,7 +94,11 @@ public class VarProcessor { - } - - public Integer getVarOriginalIndex(int index) { -- return varVersions == null ? null : varVersions.getMapOriginalVarIndices().get(index); -+ if (varVersions == null) { -+ return null; -+ } -+ final VarVersionPair pair = varVersions.getMapOriginalVarIndices().get(index); -+ return pair == null ? null : pair.var; - } - - public void refreshVarNames(VarNamesCollector vc) { -@@ -106,7 +117,9 @@ public class VarProcessor { - } - - public void setVarType(VarVersionPair pair, VarType type) { -- varVersions.setVarType(pair, type); -+ if (varVersions != null) { -+ varVersions.setVarType(pair, type); -+ } - } - - public String getVarName(VarVersionPair pair) { -@@ -152,4 +165,68 @@ public class VarProcessor { - public int getFirstParameterPosition() { - return firstParameterPosition; - } -+ -+ public List getCandidates(int origindex) { -+ if (!hasLVT()) -+ return null; -+ return method.getLocalVariableAttr().matchingVars(origindex).collect(Collectors.toList()); -+ } -+ -+ public void findLVT(VarExprent exprent, int start) { -+ if (!hasLVT()) -+ return; -+ -+ LocalVariable lvt = method.getLocalVariableAttr().getVariables() -+ .filter(v -> v.getVersion().var == exprent.getIndex() && v.getStart() == start).findFirst().orElse(null); -+ -+ if (lvt != null) { -+ exprent.setLVT(lvt); -+ } -+ } -+ -+ public void copyVarInfo(VarVersionPair from, VarVersionPair to) { -+ setVarName(to, getVarName(from)); -+ setVarFinal(to, getVarFinal(from)); -+ setVarType(to, getVarType(from)); -+ varVersions.getMapOriginalVarIndices().put(to.var, varVersions.getMapOriginalVarIndices().get(from.var)); -+ } -+ -+ public boolean hasLVT() { -+ return method.getLocalVariableAttr() != null; -+ } -+ -+ -+ public Map getLocalVariables(Statement stat) { -+ if (!hasLVT() || stat == null) -+ return new HashMap<>(); -+ -+ final StartEndPair sep = stat.getStartEndRange(); -+ final Set blacklist = new HashSet<>(); -+ Map ret = method.getLocalVariableAttr().getVariables().filter(lv -> lv.getEnd() > sep.start && lv.getStart() <= sep.end) -+ .collect(Collectors.toMap(lv -> lv.getVersion().var, lv -> lv, -+ (lv1, lv2) -> -+ { -+ //System.out.println("DUPLICATE INDEX FOR SCOPE: (" +sep +") " + lv1.toString() + " " + lv2.toString()); -+ blacklist.add(lv1.getVersion().var); -+ return lv1; -+ } -+ )); -+ -+ for (Integer b : blacklist) -+ ret.remove(b); -+ -+ return ret; -+ } -+ -+ public VarVersionsProcessor getVarVersions() { -+ return varVersions; -+ } -+ -+ public void setVarLVT(VarVersionPair var, LocalVariable lvt) { -+ mapVarLVTs.put(var, lvt); -+ } -+ -+ public LocalVariable getVarLVT(VarVersionPair var) { -+ return mapVarLVTs.get(var); -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java -index ac06d30f079427a287b62f6851f008eac39b402c..293fdc6cba46ed47259c786c940488bb1d74fba9 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java -@@ -193,7 +193,12 @@ public class VarTypeProcessor { - allExprents.add(currExprent); - for (Exprent exprent : allExprents) { - if (exprent.type == Exprent.EXPRENT_VAR) { -- ((VarExprent)exprent).setVarType(VarType.VARTYPE_UNKNOWN); -+ VarExprent ve = (VarExprent)exprent; -+ if (ve.getLVT() != null) { -+ ve.setVarType(ve.getLVT().getVarType()); -+ } else { -+ ve.setVarType(VarType.VARTYPE_UNKNOWN); -+ } - } - else if (exprent.type == Exprent.EXPRENT_CONST) { - ConstExprent constExprent = (ConstExprent)exprent; -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -index d6a9c2a29c73d778eb383d718094b7548d14d2f3..b11ff686109fd466c3b07e853fd433e5677fbf9e 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java -@@ -22,7 +22,7 @@ import java.util.Map.Entry; - - public class VarVersionsProcessor { - private final StructMethod method; -- private Map mapOriginalVarIndices = Collections.emptyMap(); -+ private Map mapOriginalVarIndices = Collections.emptyMap(); - private final VarTypeProcessor typeProcessor; - - public VarVersionsProcessor(StructMethod mt, MethodDescriptor md) { -@@ -43,7 +43,7 @@ public class VarVersionsProcessor { - - typeProcessor.calculateVarTypes(root, graph); - -- simpleMerge(typeProcessor, graph, method); -+ //simpleMerge(typeProcessor, graph, method); - - // FIXME: advanced merging - -@@ -245,7 +245,8 @@ public class VarVersionsProcessor { - CounterContainer counters = DecompilerContext.getCounterContainer(); - - final Map mapVarPaar = new HashMap<>(); -- Map mapOriginalVarIndices = new HashMap<>(); -+ Map mapOriginalVarIndices = new HashMap<>(); -+ mapOriginalVarIndices.putAll(this.mapOriginalVarIndices); - - // map var-version pairs on new var indexes - List vvps = new ArrayList<>(mapExprentMinTypes.keySet()); -@@ -266,7 +267,7 @@ public class VarVersionsProcessor { - } - - mapVarPaar.put(pair, newIndex); -- mapOriginalVarIndices.put(newIndex, pair.var); -+ mapOriginalVarIndices.put(newIndex, pair); - } - } - -@@ -296,11 +297,11 @@ public class VarVersionsProcessor { - }); - - if (previousVersionsProcessor != null) { -- Map oldIndices = previousVersionsProcessor.getMapOriginalVarIndices(); -+ Map oldIndices = previousVersionsProcessor.getMapOriginalVarIndices(); - this.mapOriginalVarIndices = new HashMap<>(mapOriginalVarIndices.size()); -- for (Entry entry : mapOriginalVarIndices.entrySet()) { -- Integer value = entry.getValue(); -- Integer oldValue = oldIndices.get(value); -+ for (Entry entry : mapOriginalVarIndices.entrySet()) { -+ VarVersionPair value = entry.getValue(); -+ VarVersionPair oldValue = oldIndices.get(value.var); - value = oldValue != null ? oldValue : value; - this.mapOriginalVarIndices.put(entry.getKey(), value); - } -@@ -327,7 +328,11 @@ public class VarVersionsProcessor { - typeProcessor.getFinalVariables().put(pair, finalType); - } - -- public Map getMapOriginalVarIndices() { -+ public Map getMapOriginalVarIndices() { - return mapOriginalVarIndices; - } -+ -+ public VarTypeProcessor getTypeProcessor() { -+ return typeProcessor; -+ } - } -\ No newline at end of file -diff --git a/src/org/jetbrains/java/decompiler/struct/StructContext.java b/src/org/jetbrains/java/decompiler/struct/StructContext.java -index a929aca1f633a76660111010256dae0ef014f6fd..2f55882afdd1dd1b9960aa0c2a007069204797e9 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructContext.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructContext.java -@@ -164,4 +164,30 @@ public class StructContext { - public Map getClasses() { - return classes; - } -+ -+ public boolean instanceOf(String valclass, String refclass) { -+ if (valclass.equals(refclass)) { -+ return true; -+ } -+ -+ StructClass cl = this.getClass(valclass); -+ if (cl == null) { -+ return false; -+ } -+ -+ if (cl.superClass != null && this.instanceOf(cl.superClass.getString(), refclass)) { -+ return true; -+ } -+ -+ int[] interfaces = cl.getInterfaces(); -+ for (int i = 0; i < interfaces.length; i++) { -+ String intfc = cl.getPool().getPrimitiveConstant(interfaces[i]).getString(); -+ -+ if (this.instanceOf(intfc, refclass)) { -+ return true; -+ } -+ } -+ -+ return false; -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/StructMember.java b/src/org/jetbrains/java/decompiler/struct/StructMember.java -index 2802eeb66f3144e8b552bd0f14674f768de51219..fb981815b90be8e4ac95bca68d3a8faebdf96b7d 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructMember.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructMember.java -@@ -18,9 +18,11 @@ import java.util.*; - import java.util.stream.Collectors; - import java.util.stream.Stream; - -+import static org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute.*; -+ - public abstract class StructMember { -- private final int accessFlags; -- private final Map attributes; -+ protected int accessFlags; -+ protected Map attributes; - - protected StructMember(int accessFlags, Map attributes) { - this.accessFlags = accessFlags; -@@ -111,6 +113,20 @@ public abstract class StructMember { - } - } - -+ if (attributes.containsKey(ATTRIBUTE_LOCAL_VARIABLE_TABLE.name) && attributes.containsKey(ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.name)) -+ ((StructLocalVariableTableAttribute)attributes.get(ATTRIBUTE_LOCAL_VARIABLE_TABLE.name)).mergeSignatures((StructLocalVariableTypeTableAttribute)attributes.get(ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.name)); - return attributes; - } -+ -+ protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException { -+ StructGeneralAttribute attribute = StructGeneralAttribute.createAttribute(name); -+ int length = in.readInt(); -+ if (attribute == null) { -+ in.discard(length); -+ } -+ else { -+ attribute.initContent(in, pool); -+ } -+ return attribute; -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java -index 465687e365cc32acac0d5aef20e96b5af209f7d6..ebc0b97de43fcd3f7e629031fb5da58f24b798ea 100644 ---- a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java -+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java -@@ -1,7 +1,10 @@ - // Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - package org.jetbrains.java.decompiler.struct.attr; - -+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; - import org.jetbrains.java.decompiler.struct.consts.ConstantPool; -+import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.util.DataInputFullStream; - - import java.io.IOException; -@@ -21,12 +24,14 @@ import java.util.stream.Stream; - */ - public class StructLocalVariableTableAttribute extends StructGeneralAttribute { - private List localVariables = Collections.emptyList(); -+ private Map indexVersion = new HashMap<>(); - - @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { - int len = data.readUnsignedShort(); - if (len > 0) { - localVariables = new ArrayList<>(len); -+ indexVersion = new HashMap<>(); - - for (int i = 0; i < len; i++) { - int start_pc = data.readUnsignedShort(); -@@ -40,6 +45,8 @@ public class StructLocalVariableTableAttribute extends StructGeneralAttribute { - pool.getPrimitiveConstant(descriptorIndex).getString(), - varIndex)); - } -+ Collections.sort(localVariables); -+ versionVariables(localVariables); - } - else { - localVariables = Collections.emptyList(); -@@ -48,6 +55,7 @@ public class StructLocalVariableTableAttribute extends StructGeneralAttribute { - - public void add(StructLocalVariableTableAttribute attr) { - localVariables.addAll(attr.localVariables); -+ versionVariables(localVariables); - } - - public String getName(int index, int visibleOffset) { -@@ -58,24 +66,57 @@ public class StructLocalVariableTableAttribute extends StructGeneralAttribute { - return matchingVars(index, visibleOffset).map(v -> v.descriptor).findFirst().orElse(null); - } - -- private Stream matchingVars(int index, int visibleOffset) { -+ public Stream matchingVars(int index, int visibleOffset) { - return localVariables.stream().filter(v -> v.index == index && (visibleOffset >= v.start_pc && visibleOffset < v.start_pc + v.length)); - } - -+ public Stream matchingVars(int index) { -+ return localVariables.stream().filter(v -> v.index == index); -+ } -+ -+ public Stream matchingVars(Statement stat) { -+ BitSet values = new BitSet(); -+ stat.getOffset(values); -+ return getRange(values.nextSetBit(0), values.length() - 1); -+ } -+ -+ public Stream getRange(int start, int end) { -+ return localVariables.stream().filter(v -> v.getStart() >= start && v.getEnd() <= end); -+ } -+ - public boolean containsName(String name) { - return localVariables.stream().anyMatch(v -> Objects.equals(v.name, name)); - } - -- public Map getMapParamNames() { -- return localVariables.stream().filter(v -> v.start_pc == 0).collect(Collectors.toMap(v -> v.index, v -> v.name, (n1, n2) -> n2)); -+ public Map getMapNames() { -+ return localVariables.stream().collect(Collectors.toMap(v -> v.version, v -> v.name, (n1, n2) -> n2)); - } - -- private static final class LocalVariable { -+ public Stream getVariables() { -+ return localVariables.stream(); -+ } -+ -+ private void versionVariables(List vars) { -+ for (LocalVariable var : vars) { -+ Integer version = indexVersion.get(var.index); -+ version = version == null ? 1 : version++; -+ indexVersion.put(var.index, version); -+ var.version = new VarVersionPair(var.index, version.intValue()); -+ } -+ } -+ -+ public void mergeSignatures(StructLocalVariableTypeTableAttribute lvtt) { -+ lvtt.backingAttribute.localVariables.stream().forEach(type -> localVariables.stream().filter(t -> t.compareTo(type) == 0).findFirst().ifPresent(lv -> lv.signature = type.descriptor)); -+ } -+ -+ public static class LocalVariable implements Comparable { - final int start_pc; - final int length; - final String name; - final String descriptor; - final int index; -+ private String signature; -+ private VarVersionPair version; - - private LocalVariable(int start_pc, int length, String name, String descriptor, int index) { - this.start_pc = start_pc; -@@ -83,6 +124,53 @@ public class StructLocalVariableTableAttribute extends StructGeneralAttribute { - this.name = name; - this.descriptor = descriptor; - this.index = index; -+ this.version = new VarVersionPair(index, 0); -+ } -+ -+ @Override -+ public int compareTo(LocalVariable o) { -+ if (this.index != o.index) return this.index - o.index; -+ if (this.start_pc != o.start_pc) return this.start_pc - o.start_pc; -+ return this.length - o.length; -+ } -+ -+ public String getName() { -+ return name; -+ } -+ -+ public String getDescriptor() { -+ return descriptor; -+ } -+ -+ public String getSignature() { -+ return signature; -+ } -+ -+ public int getStart() { -+ return start_pc; -+ } -+ -+ public int getEnd() { -+ return start_pc + length; -+ } -+ -+ public VarVersionPair getVersion() { -+ return version; -+ } -+ -+ public VarType getVarType() { -+ return new VarType(descriptor); -+ } -+ -+ @Override -+ public String toString() { -+ return "\'("+index+","+start_pc+'-'+getEnd()+")"+descriptor+(signature!=null ? "<"+signature+"> ":" ")+name+"\'"; -+ } -+ -+ public LocalVariable rename(String newName) { -+ LocalVariable ret = new LocalVariable(start_pc, length, newName, descriptor, index); -+ ret.signature = signature; -+ return ret; - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java -index 829c78e8a1361bb88cb700696c22af4f7d36349d..cfdda0f2830307d34dfcc3c0a0714f6e0693f3eb 100644 ---- a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java -+++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java -@@ -17,7 +17,7 @@ import java.io.IOException; - */ - public class StructLocalVariableTypeTableAttribute extends StructGeneralAttribute { - // store signature instead of descriptor -- private final StructLocalVariableTableAttribute backingAttribute = new StructLocalVariableTableAttribute(); -+ final StructLocalVariableTableAttribute backingAttribute = new StructLocalVariableTableAttribute(); - - @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { -diff --git a/src/org/jetbrains/java/decompiler/util/DebugPrinter.java b/src/org/jetbrains/java/decompiler/util/DebugPrinter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..311db9ff7f0c543b3d131f588baed0d92394d93c ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/util/DebugPrinter.java -@@ -0,0 +1,92 @@ -+package org.jetbrains.java.decompiler.util; -+ -+import java.util.BitSet; -+ -+import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; -+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.*; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.*; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; -+ -+//Debug printer useful for visualizing objects, no real functional value -+public class DebugPrinter { -+ public static void printMethod(Statement root, String name, VarProcessor varProc) { -+ System.out.println(name + "{"); -+ if (root == null || root.getSequentialObjects() == null) { -+ System.out.println("}"); -+ return; -+ } -+ -+ for (Object obj : root.getSequentialObjects()) { -+ if (obj instanceof Statement) { -+ printStatement((Statement)obj, " ", varProc); -+ } else if (obj == null) { -+ System.out.println(" null"); -+ } else { -+ System.out.println(" " + obj.getClass().getSimpleName()); -+ } -+ } -+ -+ if (root.type == Statement.StatementType.ROOT) { -+ printStatement(((RootStatement)root).getDummyExit(), " ", varProc); -+ } -+ System.out.println("}"); -+ } -+ -+ public static void printStatement(Statement statement, String indent, VarProcessor varProc) { -+ BitSet values = new BitSet(); -+ statement.getOffset(values); -+ int start = values.nextSetBit(0); -+ int end = values.length()-1; -+ -+ System.out.println(indent + '{' + statement.getClass().getSimpleName() + "}:" + statement.id + " (" + start + ", " + end + ")"); -+ -+ for (StatEdge edge : statement.getAllSuccessorEdges()) { -+ System.out.println(indent + " Dest: " + edge.getDestination()); -+ } -+ -+ if (statement.getExprents() != null) { -+ for(Exprent exp : statement.getExprents()) { -+ System.out.println(printExprent(indent + " ", exp, varProc)); -+ } -+ } -+ -+ indent += " "; -+ for (Object obj : statement.getSequentialObjects()) { -+ if (obj == null) { -+ System.out.println(indent + " Null"); -+ } else if (obj instanceof Statement) { -+ printStatement((Statement)obj, indent, varProc); -+ } else if (obj instanceof Exprent) { -+ System.out.println(printExprent(indent, (Exprent) obj, varProc)); -+ } else { -+ System.out.println(indent + obj.getClass().getSimpleName()); -+ } -+ } -+ } -+ -+ private static String printExprent(String indent, Exprent exp, VarProcessor varProc) { -+ StringBuffer sb = new StringBuffer(); -+ sb.append(indent); -+ BitSet values = new BitSet(); -+ exp.getBytecodeRange(values); -+ sb.append("(").append(values.nextSetBit(0)).append(", ").append(values.length()-1).append(") "); -+ sb.append(exp.getClass().getSimpleName()); -+ sb.append(" ").append(exp.id).append(" "); -+ if (exp instanceof VarExprent) { -+ VarExprent varExprent = (VarExprent)exp; -+ int currindex = varExprent.getIndex(); -+ int origindex = varProc == null ? -2 : varProc.getVarOriginalIndex(currindex); -+ sb.append("[").append(currindex).append(":").append(origindex).append(", ").append(varExprent.isStack()).append("]"); -+ if (varProc != null) { -+ sb.append(varProc.getCandidates(origindex)); -+ } -+ } else if (exp instanceof AssignmentExprent) { -+ AssignmentExprent assignmentExprent = (AssignmentExprent)exp; -+ sb.append("{").append(printExprent(" ",assignmentExprent.getLeft(),varProc)).append(" =").append(printExprent(" ",assignmentExprent.getRight(),varProc)).append("}"); -+ } else if (exp instanceof IfExprent) { -+ sb.append(' ').append(exp.toJava(0, new BytecodeMappingTracer())); -+ } -+ return sb.toString(); -+ } -+} -diff --git a/test/org/jetbrains/java/decompiler/LVTTest.java b/test/org/jetbrains/java/decompiler/LVTTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..388e1facddbac3286eaed3dbccc3b23197daf5d6 ---- /dev/null -+++ b/test/org/jetbrains/java/decompiler/LVTTest.java -@@ -0,0 +1,49 @@ -+/* -+ * Copyright 2000-2014 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler; -+ -+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; -+import org.junit.Test; -+ -+import java.io.IOException; -+import java.util.Map; -+ -+public class LVTTest extends SingleClassesTestBase { -+ @Override -+ protected Map getDecompilerOptions() { -+ return Map.of( -+ IFernflowerPreferences.DECOMPILE_INNER,"1", -+ IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES,"1", -+ IFernflowerPreferences.ASCII_STRING_CHARACTERS,"1", -+ IFernflowerPreferences.LOG_LEVEL, "TRACE", -+ IFernflowerPreferences.REMOVE_SYNTHETIC, "1", -+ IFernflowerPreferences.REMOVE_BRIDGE, "1", -+ IFernflowerPreferences.USE_DEBUG_VAR_NAMES, "1" -+ ); -+ } -+ -+ @Override -+ public void setUp() throws IOException { -+ super.setUp(); -+ fixture.setCleanup(false); -+ } -+ -+ @Test public void testLVT() { doTest("pkg/TestLVT"); } -+ @Test public void testScoping() { doTest("pkg/TestLVTScoping"); } -+ @Test public void testLVTComplex() { doTest("pkg/TestLVTComplex"); } -+ @Test public void testVarType() { doTest("pkg/TestVarType"); } -+ @Test public void testLoopMerging() { doTest("pkg/TestLoopMerging"); } -+} -diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java -index 89adb4e6fca7186ae849e62b98a9253de2dd29ef..dd0e178cc1df1c6edc9e77e3149c2b0e9bffe884 100644 ---- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java -+++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java -@@ -26,6 +26,7 @@ public class SingleClassesTest extends SingleClassesTestBase { - IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1"); - } - -+ @Test public void testEnhancedForLoops() { doTest("pkg/TestEnhancedForLoops"); } - @Test public void testPrimitiveNarrowing() { doTest("pkg/TestPrimitiveNarrowing"); } - @Test public void testClassFields() { doTest("pkg/TestClassFields"); } - @Test public void testInterfaceFields() { doTest("pkg/TestInterfaceFields"); } -diff --git a/testData/bulk/pkg/res/Loader.java b/testData/bulk/pkg/res/Loader.java -index cdb1db5b9d381f4766555df788d5e6fefc09d059..5e4c220660b40e5ba8a7f13b5516b01724c9d2d6 100644 ---- a/testData/bulk/pkg/res/Loader.java -+++ b/testData/bulk/pkg/res/Loader.java -@@ -17,8 +17,8 @@ public class Loader { - stream.read(bytes); - stream.close(); - return new String(bytes, "UTF-8"); -- } catch (Exception var5) { -- throw new RuntimeException("Resource load failed", var5); -+ } catch (Exception e) { -+ throw new RuntimeException("Resource load failed", e); - } - } - } -diff --git a/testData/classes/pkg/TestEnhancedForLoops.class b/testData/classes/pkg/TestEnhancedForLoops.class -new file mode 100644 -index 0000000000000000000000000000000000000000..bdb8a786b1c9e708620e423c250c63925ac12493 -GIT binary patch -literal 1725 -zcmaKsUsD@Z7{;HIY;w}D{3(#oR-uT61_;E)ib^mx)S}Tqs!%koH%nMy+pwG2Y@BlM -zm+(?=dgF~=q(kd;y!Os7;f&wF=}g7v>?S~IC_wm_&APUWMjCYz6CWbtKp`^ -zCla>=qDz)-d3k|wYI;*ZyXkD30{tb+HrJYaTc*2VY}FVUEIC!9wrRMQTDOCmw`(;7 -zE|uyJb}}1g!@Fhg8g|v(UUA%#S7;L54orL(2;If)gCPX&fg^4zhvoQFP+uxOiQdu%=VnsP^9;~OZu=<3RD~mQQl;H#~EXFVkr($81C|@?JtHq`TmOwSY6z3jx9B5mK<;Z35yW;^CN!AnauUJ?j!{3Dz(vmWAOV-~23JHmI{XWZMHwp$M1PN0!dkhaMaq>(v|NeG -zaz)0u=6xKr#b6T -zPC()cCdtbdZORzeQ@Bcu6r;-2ATr(N?nCGW`Xy#0W}nk!!HOMR8s+0IzXCVi!R={5 -z&y)BmdMT@Ku)l?Y(H73PFz9Re>$HYRQcRKTD)QtiP)SF_BxiGUT4`85(y)m6QyNr6 -Sy&~m(w}xwszQbq;*Zv0xhj@4Z - -literal 0 -HcmV?d00001 - -diff --git a/testData/classes/pkg/TestLVT.class b/testData/classes/pkg/TestLVT.class -new file mode 100644 -index 0000000000000000000000000000000000000000..0477af41e18fb06d5d18e3f5b693bfbb59f4ee06 -GIT binary patch -literal 1780 -zcmaJ?-%}e^6#j0w*#ln47^S!CHUz@?+WnpMrql59#mzZl?m6CWbz5LEnZIX$Yp2V0WhY(m>TYFc -z?zlze)f%O0&AFuV9E%Xp{asriSgE=VmJ{*anx0!u=iP?Ktg=zF_XLE?E2~;)1GPQY -z>>3?JP9R`UE5Ss5Mn3uA(*#c(?Qy?$*yq_EER}7(r^t=1drrxlTVR5j9yg{u!RzF> -zaKW=n_ZiV1tB#LZls`fiCDgUdYfHc?RGamZv*M}~33Ud3QS}+ZIL-(RcYD5GuiN{o -zSb>rMkMu^C>G -zyRpma706u`^o>A&44*9htDFpTd5_b4a_sYLkCmx#Ig?ARCQlwCJ!xi4i59 -zF*rUCgCAhRT4!lcI#M-bfgc5PfUA*(A8sq+e+Yv;`9q4n#=YKnM}FqQYqoiNc|$jk8KN-FhS2Df}bO -zfP@f2{Q>+a#H>L=RYCIX%$uEg<9)k7etx?I@Dz`#*ur)N9Q6uCI~F!Lb}hKgaff4% -z;UFBmQ+Yh=iAA_Ln}$P~<Ej_<3=P}T(IT04PRw8#&yJMTlfyJMsgE|A -z3>$R7&eb{L69)e{No3m9BFkjP5d7uokLNPZ=|tBX8Mdw`f6L_-qLnU$URu80R{J#i -zckMIM_BCl+|NlNW=|m+$7phaK6ZM0Ay3#UTF$?Ne1RD{)0iXOTp*dWNfYw*A%kS0C -za6Z}3{Q}SHe}MO|l*zhb$oT;l1U!g`Qog -du2$@=Q$OHglh(UrHLB<25tQk+fEZv6kVq??U_!8i^UNO^@gZzRVuftrQ8K2Rxv3yQKNAvBMwZbq@5a#kMiP^ -zPx=AG=&NF)MkC?bzwj@7689OZv=MC6bI$C&*1oKLrr&>k*#IzrnIL2&Rh&aFM>|Kq -zidGDWWl+IBm7IeDky4JTmO62-g{l{|6>d -zmKIEgmaOHN*Q>>Ovpi?a+hpM$fA#^xnOJtocw{7P!&yw`+_L2?4#oFQ9L|;shMhOc -zmIzdfCObxvf`j^&ah2X;v`6VEfq?n8?@3FfRt$8f7 -z!Vw(x{4^&*iHyCF=nL?~>F6f}-h1x)bUSp8 -zTfi7E7Om1)!7P`pvc$N6f7F>52wk&_wmU+#yJt=yFy<^+0`)n&XicuI%v+^dbG|@J -zJm=)i!kk&Mm0mRl+$Fm#(3D$!w3wN-%5H9McFb8>Em-SUdDe<)7X`!y7wh>pE^%8| -z+e51H+_L$BnJJjX#mv^Uvr+R5r8Jfv>MHS>=q%vEndi6k+Xc*_Ivj(|Sntd;WCEn6YdSUd25 -z8ppsHv`FL(Okk1-nB|4{C8i8a<85Ym6W4Zb;4WrZ!oV!vF))XF2Hr)|z$oq;cz}l- -z`?f+aH$@OkE|L~MiMK%Pzj%_ElW{3R*nEoFyA1Jv8yt77lIc37nsX~`)S5QRuC>DJ -zABmuhbl&#rEFB?c63k+)VE$NPh)Q;1kqQ -z2n$SZ9{gHk&sXg+{h2--XblVpTZ6mVkUuLEG7)-$SZgpL2eR5@$;!W+^tV*~M=hwh -z9}l(7gHN}hZy~Y`W8e#piheF1mjXzkqT~xIypH{EBBI17MdtAPIl}S!iA{v!v5Eh; -zgc!rTG}9E^0q@|C&`DWR(+IhaG$QLp|TH7#y;=MjkQ1%nbcfGx -z$>w*Y6iv5%*ex+rO^H;wa1(&q4`??eiI(E&d$;6(xw5SMY0Ua-$U(2X7lp59dT_R_Ad -zPsP_qDNV~VnhrQ%K%$>tL3H;}zmJfo?BUGcFeC;fGJhfdT!m#g3p6iWnI&F2p4zyN -rNHz8B9`vLxqrT{K_#_4+?C=sR`f!;&fynvzAH+{gBYF*JzR~s%!6|RH - -literal 0 -HcmV?d00001 - -diff --git a/testData/classes/pkg/TestLVTScoping.class b/testData/classes/pkg/TestLVTScoping.class -new file mode 100644 -index 0000000000000000000000000000000000000000..b13a2da2070ddc93780406d9b74262fec5610576 -GIT binary patch -literal 1024 -zcma)4U2hUW6g>l5mZeZWODkY&>ldIFZPgcyNn>I{N?Q{M34L4WNVkPu0!yR+#=H8h*=bU?HzW@CC4Ztp*>+lIA`WKy2T@Kx9qh4z}ear6X -z&;(-V=A~Kcns%pj+&Y(SS0M1hvMu+efInYo2xzaIQyGFEMi@&72t=!vEssXMmK@a0 -zR#y_d>a@*n!yH&DpKfaInKcwhRj)IbNz#+!-$42W5C2h!}3>JIMdxGRwKbSxf+aUXdK?yDPJn;`k$a -zzP8jOB^O_RN71umHq37VXpH#0oONa;u7c}Q@iT%S8Tb(5td3RbGUxE5fNO-AftA_i -zA*)qgPSd_1I>zb;7>OGPR|q7s2cK}WIL2*->Gv=*ya$plBS;JbaqgywnkBB{NfT{_ -zwFMNJrC2qI9xyZDi~oR6$3uoY{}vGWyMP$U;v`CN=D*{}lKTGy7!v`dnSggw2e#)9 -zM71(o&y4Z-3V)Qb;TgY9$_zWtQb3M>dV|>}pJ{6*CBnJ__Sk*KiaZ$E^a1Lv;<-CSO$MCS9;CdH;xje|1stp*ZFi?pK9Rmgi5!G?pz!@-A?GZ2qs^#5i%1kGtR})LtJQ0_e -zW^S)K)(VTrtkDsSxxscOdM#(Cof#)*nJcWc_6W0po|QqVG@0m`=$%CyTU5@zDG(AR -zH6ejgYSajxdks%fN+GS0w-B$WC*@D95 -zSq!L;o}eajgL*()+=gf4;B(RGefYTGOcb3j`IN^^TS*D%Xhs>%bDE0j$Mfmy>DL$) -z3Ndp-0m-vGlIckKwhKiG=tR=^8f7y58~7w9#b8!tu!90%t*|0WmEgEapsA0UEFp0^qE9s?!B -lJ}nTtS0Hw$gxF5_4-@+hm4eLHhC*Lq?7Khqc4AP_@dGu?5$FH_ - -literal 0 -HcmV?d00001 - -diff --git a/testData/classes/pkg/TestVarType.class b/testData/classes/pkg/TestVarType.class -new file mode 100644 -index 0000000000000000000000000000000000000000..28473768df1fca50e12184e05997281a94d1519e -GIT binary patch -literal 375 -zcmZ9Hy-veG5QJy_3&tUifl$){1#akwXpoQ)0Scn@wmF3h#*Q2ZDScju3Wiszw5 -zjGYJ&C*AGM?(DaBA78I;0FJTc!9?Jq<02F|J)P_7RABBO3@iX0 -zAWkx7!hVs)*)T43tyf8_y4O=dr$2cZMFTahSRc$M>O|ls^GfNw5{Tx$5O}x6tW4Fp -zu5rO1_t7|hihWqHIrtxm&bk_9aXyM}lCerF?7`p<>Scg0hRxHViWr5_K74^ZH)WTn -z( 7 -+24 <-> 9 -+25 <-> 10 -+27 <-> 12 -+31 <-> 15 -+32 <-> 16 -+34 <-> 18 -+38 <-> 21 -+39 <-> 22 -+41 <-> 24 -+Not mapped: -+30 -+33 -+37 -+40 -diff --git a/testData/results/TestKotlinConstructorKt.dec b/testData/results/TestKotlinConstructorKt.dec -index 0e941450d0dabcbec609f869f674d9cc5bdace33..e57e91a4d0f967a12d306f22b295608a08a872f1 100644 ---- a/testData/results/TestKotlinConstructorKt.dec -+++ b/testData/results/TestKotlinConstructorKt.dec -@@ -1,6 +1,5 @@ - import java.util.ArrayList; - import java.util.Collection; --import java.util.Iterator; - import java.util.List; - import kotlin.Metadata; - import kotlin.TypeCastException; -@@ -17,10 +16,8 @@ public final class TestKotlinConstructorKt { - private static final List foo(Collection list) { - Iterable $receiver$iv = (Iterable)list;// 2 - Collection destination$iv$iv = (Collection)(new ArrayList(CollectionsKt.collectionSizeOrDefault($receiver$iv, 10))); -- Iterator var4 = $receiver$iv.iterator();// 10 11 - -- while(var4.hasNext()) { -- Object item$iv$iv = var4.next(); -+ for(Object item$iv$iv : $receiver$iv) {// 10 11 - String it = (String)item$iv$iv; - Mapping var10000 = new Mapping; - if (it == null) {// 3 -@@ -31,100 +28,81 @@ public final class TestKotlinConstructorKt { - Mapping var11 = var10000; - destination$iv$iv.add(var11);// 12 - } -- -- return CollectionsKt.toList((Iterable)((List)destination$iv$iv));// 4 13 -+// 4 13 -+ return CollectionsKt.toList((Iterable)((List)destination$iv$iv)); - } - } - - class 'TestKotlinConstructorKt' { - method 'foo (Ljava/util/Collection;)Ljava/util/List;' { -- 0 17 -- 1 17 -- 2 17 -- 3 17 -- 4 17 -+ 0 16 -+ 1 16 -+ 2 16 -+ 3 16 -+ 4 16 - 6 19 -- c 18 -- d 18 -- e 18 -- f 18 -- 10 18 -- 11 18 -- 15 18 -- 16 18 -- 17 18 -- 18 18 -- 1b 19 -- 1c 19 -- 1d 19 -- 1e 19 -- 1f 19 -+ c 17 -+ d 17 -+ e 17 -+ f 17 -+ 10 17 -+ 11 17 -+ 15 17 -+ 16 17 -+ 17 17 -+ 18 17 - 20 19 - 21 19 -- 22 21 -- 23 21 -- 24 21 -- 25 21 -- 26 21 -- 27 21 -- 28 21 -- 2c 22 -- 2d 22 -- 2e 22 -- 2f 22 -- 30 22 -- 31 22 -- 32 22 -- 33 22 -- 34 22 -- 35 31 -- 36 23 -- 37 23 -- 38 23 -- 39 23 -- 3a 23 -- 3b 23 -- 3c 23 -- 43 25 -- 44 25 -- 46 25 -- 4d 26 -- 4e 26 -- 52 26 -- 53 29 -- 54 29 -- 55 29 -- 56 29 -- 57 29 -- 58 29 -- 59 30 -- 5a 30 -- 5d 31 -- 5e 31 -- 5f 31 -- 60 31 -- 61 31 -- 62 31 -- 63 31 -- 68 34 -- 69 34 -- 6a 34 -- 6b 34 -- 6c 34 -- 6d 34 -- 6e 34 -- 6f 34 -- 70 34 -- 71 34 -- 72 34 -+ 33 19 -+ 34 19 -+ 35 28 -+ 36 20 -+ 37 20 -+ 38 20 -+ 39 20 -+ 3a 20 -+ 3b 20 -+ 3c 20 -+ 43 22 -+ 44 22 -+ 46 22 -+ 4d 23 -+ 4e 23 -+ 52 23 -+ 53 26 -+ 54 26 -+ 55 26 -+ 56 26 -+ 57 26 -+ 58 26 -+ 59 27 -+ 5a 27 -+ 5d 28 -+ 5e 28 -+ 5f 28 -+ 60 28 -+ 61 28 -+ 62 28 -+ 63 28 -+ 68 30 -+ 69 30 -+ 6a 30 -+ 6b 30 -+ 6c 30 -+ 6d 30 -+ 6e 30 -+ 6f 30 -+ 70 30 -+ 71 30 -+ 72 30 - } - } - - Lines mapping: --2 <-> 18 --3 <-> 26 --4 <-> 35 -+2 <-> 17 -+3 <-> 23 -+4 <-> 31 - 10 <-> 20 - 11 <-> 20 --12 <-> 32 --13 <-> 35 -+12 <-> 29 -+13 <-> 31 -diff --git a/testData/results/TestLVT.dec b/testData/results/TestLVT.dec -new file mode 100644 -index 0000000000000000000000000000000000000000..a78cf6ee711a1115ed42c227a630086dd8bcff8b ---- /dev/null -+++ b/testData/results/TestLVT.dec -@@ -0,0 +1,39 @@ -+package pkg; -+ -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+ -+public class TestLVT { -+ public static void method(String a1, String a2) { -+ String scope1 = "scope1"; -+ String scope1a = "scope1a"; -+ -+ for(int i = 0; i < 10; ++i) { -+ String scope2 = "scope2"; -+ String scope2a = "scope2a"; -+ List noise = new ArrayList(); -+ String spam = scope1 + scope2 + scope2a + i + noise; -+ System.out.println(spam); -+ } -+ -+ for(long i = 0L; i < 10L; ++i) { -+ String scope2 = "scope2+1"; -+ String scope2a = "scope2+1a"; -+ Map noise = new HashMap(); -+ String spam = scope1a + scope2 + scope2a + i + noise; -+ System.out.println(spam); -+ } -+ -+ } -+ -+ public void methoda() { -+ double a = 0.0D; -+ double b = 1.0D; -+ System.out.println(a + b); -+ a = 0.1D; -+ b = 1.1D; -+ System.out.println(a + b); -+ } -+} -diff --git a/testData/results/TestLVTComplex.dec b/testData/results/TestLVTComplex.dec -new file mode 100644 -index 0000000000000000000000000000000000000000..7d492ca4a8dcba8dae51f5d2d8f4a086022aef2a ---- /dev/null -+++ b/testData/results/TestLVTComplex.dec -@@ -0,0 +1,84 @@ -+package pkg; -+ -+import java.util.ArrayList; -+ -+public class TestLVTComplex { -+ public static void main() { -+ int[] x = new int[5]; -+ -+ for(int y : x) { -+ ; -+ } -+ -+ for(int y : x) { -+ System.out.println("asdf"); -+ } -+ -+ ArrayList x1 = new ArrayList(); -+ -+ for(Object y : x1) { -+ ; -+ } -+ -+ for(Object y : x1) { -+ int[] x2 = new int[10]; -+ -+ for(int y2 : x2) { -+ ; -+ -+ } -+ -+ for(int y2 : x2) { -+ System.out.println("asdf"); -+ -+ } -+ -+ System.out.println("asdf"); -+ } -+ -+ switch(Bob.HI) { -+ case HI: -+ System.out.println("HI"); -+ break; -+ case LO: -+ System.out.println("LO"); -+ } -+ -+ if (TestLVTComplex.Bob.HI == TestLVTComplex.Bob.HI) { -+ String a = "a"; -+ } else { -+ String b = "b"; -+ } -+ -+ String a2; -+ if (TestLVTComplex.Bob.HI == TestLVTComplex.Bob.HI) { -+ a2 = "a"; -+ } else { -+ a2 = "b"; -+ } -+ -+ if (TestLVTComplex.Bob.HI == TestLVTComplex.Bob.HI) { -+ a2 = "a"; -+ } -+ -+ System.out.println(a2); -+ } -+ -+ private static enum Bob { -+ HI, -+ LO; -+ -+ static { -+ for(TestLVTComplex.Bob b : values()) { -+ for(TestLVTComplex.Bob c : values()) { -+ for(TestLVTComplex.Bob d : values()) { -+ if (b == c) { -+ System.out.println("Asdf"); -+ } -+ } -+ } -+ } -+ -+ } -+ } -+} -diff --git a/testData/results/TestLVTScoping.dec b/testData/results/TestLVTScoping.dec -new file mode 100644 -index 0000000000000000000000000000000000000000..74941fbba151492665389134b3d925e57f4801a7 ---- /dev/null -+++ b/testData/results/TestLVTScoping.dec -@@ -0,0 +1,35 @@ -+package pkg; -+ -+public class TestLVTScoping { -+ public static void method() { -+ String a; -+ if (1 == Integer.valueOf(1).intValue()) { -+ a = "YAY"; -+ } else { -+ a = "NAY"; -+ } -+ -+ System.out.println(a); -+ } -+ -+ public static void method2() { -+ if (1 == Integer.valueOf(1).intValue()) { -+ String a = "YAY"; -+ } else { -+ String a = "NAY"; -+ System.out.println(a); -+ } -+ -+ } -+ -+ public static void method3() { -+ if (1 == Integer.valueOf(1).intValue()) { -+ boolean a = true; -+ System.out.println(a); -+ } else { -+ String a = "NAY"; -+ System.out.println(a); -+ } -+ -+ } -+} -diff --git a/testData/results/TestLocalsNames.dec b/testData/results/TestLocalsNames.dec -index 59563ddeb1c2cb82405b31d9f0073a1df450c9e8..1041a5490d33ee05ccb669d924c3fac80f6e134f 100644 ---- a/testData/results/TestLocalsNames.dec -+++ b/testData/results/TestLocalsNames.dec -@@ -7,21 +7,18 @@ public class TestLocalsNames { - if (file.isDirectory()) {// 22 - long start = System.currentTimeMillis();// 23 - File[] files = file.listFiles();// 25 -- File[] var5 = files; -- int var6 = files.length; - -- for(int var7 = 0; var7 < var6; ++var7) {// 26 -- File s = var5[var7]; -+ for(File s : files) {// 26 - File dest = new File(s.getAbsolutePath() + ".tmp");// 27 - - assert s.renameTo(dest) : "unable to rename " + s + " to " + dest;// 28 - } -- -- long elapsed = System.currentTimeMillis() - start;// 31 -- System.out.println("took " + elapsed + "ms (" + elapsed / (long)files.length + "ms per dir)");// 32 -+// 31 -+ long elapsed = System.currentTimeMillis() - start;// 32 -+ System.out.println("took " + elapsed + "ms (" + elapsed / (long)files.length + "ms per dir)"); - } -- -- }// 34 -+// 34 -+ } - } - - class 'pkg/TestLocalsNames' { -@@ -41,91 +38,79 @@ class 'pkg/TestLocalsNames' { - e 8 - f 8 - 10 8 -- 11 9 -- 12 9 -- 13 9 -- 14 9 -- 17 10 -+ 11 10 -+ 12 10 -+ 13 10 -+ 14 10 - 18 10 - 19 10 -- 1a 12 -- 1b 12 -- 1c 12 -- 1d 12 -- 1e 12 -- 1f 12 -- 20 12 -- 21 12 -- 24 13 -- 25 13 -- 26 13 -- 27 13 -- 28 13 -- 29 13 -- 2a 13 -- 36 14 -- 37 14 -- 38 14 -- 39 14 -- 3a 14 -- 3e 14 -- 3f 14 -- 43 14 -- 44 14 -- 45 14 -- 49 14 -- 4a 14 -- 51 16 -- 52 16 -- 53 16 -- 54 16 -- 55 16 -- 56 16 -- 57 16 -- 66 16 -- 67 16 -- 6b 16 -- 6c 16 -- 70 16 -- 71 16 -- 75 16 -- 76 16 -- 7a 16 -- 7b 16 -- 7c 16 -- 81 12 -- 82 12 -- 83 12 -- 87 19 -- 88 19 -- 89 19 -- 8a 19 -- 8b 19 -- 8c 19 -- 8d 19 -- 8e 20 -- 8f 20 -- 90 20 -- 98 20 -- 99 20 -- 9d 20 -- 9e 20 -- a2 20 -- a3 20 -- a7 20 -- a8 20 -- a9 20 -- aa 20 -- ab 20 -- ac 20 -- ad 20 -- b1 20 -- b2 20 -- b6 20 -- b7 20 -- b8 20 -- b9 20 -- bc 23 -+ 1b 10 -+ 1c 10 -+ 29 10 -+ 2a 10 -+ 36 11 -+ 37 11 -+ 38 11 -+ 39 11 -+ 3a 11 -+ 3e 11 -+ 3f 11 -+ 43 11 -+ 44 11 -+ 45 11 -+ 49 11 -+ 4a 11 -+ 51 13 -+ 52 13 -+ 53 13 -+ 54 13 -+ 55 13 -+ 56 13 -+ 57 13 -+ 66 13 -+ 67 13 -+ 6b 13 -+ 6c 13 -+ 70 13 -+ 71 13 -+ 75 13 -+ 76 13 -+ 7a 13 -+ 7b 13 -+ 7c 13 -+ 81 10 -+ 82 10 -+ 83 10 -+ 87 15 -+ 88 15 -+ 89 15 -+ 8a 15 -+ 8b 15 -+ 8c 15 -+ 8d 15 -+ 8e 16 -+ 8f 16 -+ 90 16 -+ 98 16 -+ 99 16 -+ 9d 16 -+ 9e 16 -+ a2 16 -+ a3 16 -+ a7 16 -+ a8 16 -+ a9 16 -+ aa 16 -+ ab 16 -+ ac 16 -+ ad 16 -+ b1 16 -+ b2 16 -+ b6 16 -+ b7 16 -+ b8 16 -+ b9 16 -+ bc 19 - } - } - -@@ -133,9 +118,9 @@ Lines mapping: - 22 <-> 7 - 23 <-> 8 - 25 <-> 9 --26 <-> 13 --27 <-> 15 --28 <-> 17 --31 <-> 20 --32 <-> 21 --34 <-> 24 -+26 <-> 11 -+27 <-> 12 -+28 <-> 14 -+31 <-> 16 -+32 <-> 17 -+34 <-> 20 -diff --git a/testData/results/TestLoopMerging.dec b/testData/results/TestLoopMerging.dec -new file mode 100644 -index 0000000000000000000000000000000000000000..703203a5dad69c818eac940996013864c2167da5 ---- /dev/null -+++ b/testData/results/TestLoopMerging.dec -@@ -0,0 +1,82 @@ -+package pkg; -+ -+public class TestLoopMerging { -+ public float a; -+ public float b; -+ -+ public float test() { -+ while(this.a - this.b < -180.0F) { -+ this.b -= 360.0F; -+ } -+ -+ while(this.a - this.b >= 180.0F) { -+ this.b += 360.0F; -+ } -+ -+ return this.a; -+ } -+ -+ public float test2() { -+ for(this.a = 0.0F; this.a < 10.0F; ++this.a) { -+ System.out.println(this.a); -+ } -+ -+ for(this.a = 0.0F; this.a < 10.0F; ++this.a) { -+ System.out.println(this.a); -+ } -+ -+ return this.a; -+ } -+ -+ public float test3() { -+ int[] as = new int[0]; -+ -+ for(int f : as) { -+ ++f; -+ } -+ -+ while(this.a - this.b < -180.0F) { -+ this.b -= 360.0F; -+ } -+ -+ while(this.a - this.b >= 180.0F) { -+ this.b += 360.0F; -+ } -+ -+ for(this.a = 0.0F; this.a < 10.0F; ++this.a) { -+ System.out.println(this.a); -+ } -+ -+ return this.a; -+ } -+ -+ public float test4() { -+ int[] as = new int[0]; -+ -+ for(int f : as) { -+ ++f; -+ -+ while(this.a - this.b < -180.0F) { -+ this.b -= 360.0F; -+ } -+ -+ while(this.a - this.b >= 180.0F) { -+ this.b += 360.0F; -+ } -+ -+ for(this.a = 0.0F; this.a < 10.0F; ++this.a) { -+ System.out.println(this.a); -+ -+ while(this.a - this.b < -180.0F) { -+ this.b -= 360.0F; -+ } -+ -+ while(this.a - this.b >= 180.0F) { -+ this.b += 360.0F; -+ } -+ } -+ } -+ -+ return this.a; -+ } -+} -diff --git a/testData/results/TestTryCatchFinally.dec b/testData/results/TestTryCatchFinally.dec -index 20e9afb72b2d2dabc76d29f6bb1f4ef2bfbc5a20..0caaede304ce41149b60846857bba24468c99675 100644 ---- a/testData/results/TestTryCatchFinally.dec -+++ b/testData/results/TestTryCatchFinally.dec -@@ -4,7 +4,7 @@ public class TestTryCatchFinally { - public void test1(String var1) { - try { - System.out.println("sout1");// 24 -- } catch (Exception var9) { -+ } catch (Exception var2) { - try { - System.out.println("sout2");// 27 - } catch (Exception var8) {// 28 -diff --git a/testData/results/TestVarType.dec b/testData/results/TestVarType.dec -new file mode 100644 -index 0000000000000000000000000000000000000000..56fb422828fe9a4985f892122d46051d3cd1f73b ---- /dev/null -+++ b/testData/results/TestVarType.dec -@@ -0,0 +1,9 @@ -+package pkg; -+ -+public class TestVarType { -+ public void byteint() { -+ int i = 75; -+ i = i + 5; -+ i = i + 500; -+ } -+} -diff --git a/testData/src/pkg/TestEnhancedForLoops.java b/testData/src/pkg/TestEnhancedForLoops.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d808218357900a716e43edca3b7146f1a01add13 ---- /dev/null -+++ b/testData/src/pkg/TestEnhancedForLoops.java -@@ -0,0 +1,42 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package pkg; -+ -+import java.util.List; -+import java.util.ArrayList; -+ -+public class TestEnhancedForLoops { -+ public void forArray() { -+ int[] numbers = {1, 2, 3, 4, 5, 6}; -+ for (int number : numbers) { -+ System.out.println(number); -+ } -+ } -+ -+ public void forItterator() { -+ List strings = new ArrayList<>(); -+ for (String string : strings) { -+ System.out.println(string); -+ } -+ } -+ -+ public void forItteratorUnboxing() { -+ List ints = new ArrayList<>(); -+ for (int i : ints) { -+ System.out.println("Value: " + i); -+ } -+ } -+} -diff --git a/testData/src/pkg/TestLVT.java b/testData/src/pkg/TestLVT.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b9eed0dc1287fbabc4a400444b32b087831ffc66 ---- /dev/null -+++ b/testData/src/pkg/TestLVT.java -@@ -0,0 +1,36 @@ -+package pkg; -+ -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+ -+public class TestLVT { -+ public static void method(String a1, String a2) { -+ String scope1 = "scope1"; -+ String scope1a = "scope1a"; -+ for (int i=0; i<10; i++) { -+ String scope2 = "scope2"; -+ String scope2a = "scope2a"; -+ List noise = new ArrayList(); -+ String spam = scope1 + scope2 + scope2a + i + noise; -+ System.out.println(spam); -+ } -+ for (long i=0; i<10; i++) { -+ String scope2 = "scope2+1"; -+ String scope2a = "scope2+1a"; -+ Map noise = new HashMap(); -+ String spam = scope1a + scope2 + scope2a + i + noise; -+ System.out.println(spam); -+ } -+ } -+ -+ public void methoda() { -+ double a = 0D; -+ double b = 1D; -+ System.out.println(a+b); -+ a = 0.1D; -+ b = 1.1D; -+ System.out.println(a+b); -+ } -+} -diff --git a/testData/src/pkg/TestLVTComplex.java b/testData/src/pkg/TestLVTComplex.java -new file mode 100644 -index 0000000000000000000000000000000000000000..548b9fd5883d6c9d2f706e8f97c93e42ace808f1 ---- /dev/null -+++ b/testData/src/pkg/TestLVTComplex.java -@@ -0,0 +1,64 @@ -+package pkg; -+ -+import java.util.ArrayList; -+ -+public class TestLVTComplex { -+ public static void main() { -+ int[] x = new int[5]; -+ for (int y : x) -+ ; -+ for (int y : x) { -+ System.out.println("asdf"); -+ } -+ ArrayList x1 = new ArrayList(); -+ for (Object y : x1) -+ ; -+ for (Object y : x1) { -+ int[] x2 = new int[10]; -+ for (int y2 : x2) -+ ; -+ for (int y2 : x2) { -+ System.out.println("asdf"); -+ } -+ System.out.println("asdf"); -+ } -+ switch (Bob.HI) { -+ case HI: -+ System.out.println("HI"); -+ break; -+ case LO: -+ System.out.println("LO"); -+ break; -+ } -+ if (Bob.HI == Bob.HI) { -+ String a = "a"; -+ } else { -+ String b = "b"; -+ } -+ String a2; -+ if (Bob.HI == Bob.HI) { -+ a2 = "a"; -+ } else { -+ a2 = "b"; -+ } -+ if (Bob.HI == Bob.HI) { -+ a2 = "a"; -+ } -+ System.out.println(a2); -+ -+ } -+ -+ private static enum Bob { -+ HI, LO; -+ static { -+ for (Bob b : Bob.values()) { -+ for (Bob c : values()) { -+ for (Bob d : values()) { -+ if (b == c) -+ System.out.println("Asdf"); -+ } -+ } -+ } -+ }; -+ } -+} -diff --git a/testData/src/pkg/TestLVTScoping.java b/testData/src/pkg/TestLVTScoping.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ab57832c2f3df13a4ae9da2af193c2d6a79067ab ---- /dev/null -+++ b/testData/src/pkg/TestLVTScoping.java -@@ -0,0 +1,34 @@ -+package pkg; -+ -+ -+public class TestLVTScoping { -+ public static void method() { -+ String a; -+ if (1 == Integer.valueOf(1)) { -+ a = "YAY"; -+ } else { -+ a = "NAY"; -+ } -+ System.out.println(a); -+ } -+ public static void method2() { -+ String a; -+ if (1 == Integer.valueOf(1)) { -+ a = "YAY"; -+ } else { -+ a = "NAY"; -+ System.out.println(a); -+ } -+ } -+ public static void method3() { -+ if (1 == Integer.valueOf(1)) { -+ boolean a; -+ a = true; -+ System.out.println(a); -+ } else { -+ String a; -+ a = "NAY"; -+ System.out.println(a); -+ } -+ } -+} -diff --git a/testData/src/pkg/TestLoopMerging.java b/testData/src/pkg/TestLoopMerging.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1643c8137282657c42f090481a16d0ed5b34e93f ---- /dev/null -+++ b/testData/src/pkg/TestLoopMerging.java -@@ -0,0 +1,47 @@ -+package pkg; -+ -+public class TestLoopMerging { -+ public float a; -+ public float b; -+ public float test() { -+ while(a - b < -180) b -= 360; -+ while(a - b >= 180) b += 360; -+ return a; -+ } -+ public float test2() { -+ for (a = 0; a < 10; a++) { -+ System.out.println(a); -+ } -+ for (a = 0; a < 10; a++) { -+ System.out.println(a); -+ } -+ return a; -+ } -+ -+ public float test3() { -+ int[] as = new int[0]; -+ for (int f: as) { -+ f++; -+ } -+ while(this.a - this.b < -180) this.b -= 360; -+ while(this.a - this.b >= 180) this.b += 360; -+ for (a = 0; a < 10; a++) { -+ System.out.println(a); -+ } -+ return this.a; -+ } -+ public float test4() { -+ int[] as = new int[0]; -+ for (int f: as) { -+ f++; -+ while(this.a - this.b < -180) this.b -= 360; -+ while(this.a - this.b >= 180) this.b += 360; -+ for (a = 0; a < 10; a++) { -+ System.out.println(a); -+ while(this.a - this.b < -180) this.b -= 360; -+ while(this.a - this.b >= 180) this.b += 360; -+ } -+ } -+ return this.a; -+ } -+} -diff --git a/testData/src/pkg/TestVarType.java b/testData/src/pkg/TestVarType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..15e2171a235562128cdb80c64f1acdacaa05c387 ---- /dev/null -+++ b/testData/src/pkg/TestVarType.java -@@ -0,0 +1,24 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package pkg; -+ -+public class TestVarType { -+ public void byteint() { -+ int i = 75; -+ i+=5; -+ i+=500; -+ } -+} diff --git a/FernFlower-Patches/0009-Merge-any-LVTT-to-an-incoming-LVT-if-they-re-out-of-.patch b/FernFlower-Patches/0009-Merge-any-LVTT-to-an-incoming-LVT-if-they-re-out-of-.patch new file mode 100644 index 0000000..ff0ca23 --- /dev/null +++ b/FernFlower-Patches/0009-Merge-any-LVTT-to-an-incoming-LVT-if-they-re-out-of-.patch @@ -0,0 +1,33 @@ +From 7d5770f2462f354c4663f77818ae718062689d7b Mon Sep 17 00:00:00 2001 +From: cpw +Date: Sun, 2 Aug 2015 20:56:16 -0400 +Subject: [PATCH 009/122] Merge any LVTT to an incoming LVT (if they're out of + sequence), and merge LVTTs together if there's no LVT yet. + +--- + .../jetbrains/java/decompiler/struct/StructMember.java | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/org/jetbrains/java/decompiler/struct/StructMember.java b/src/org/jetbrains/java/decompiler/struct/StructMember.java +index 724c0db..af1df05 100644 +--- a/src/org/jetbrains/java/decompiler/struct/StructMember.java ++++ b/src/org/jetbrains/java/decompiler/struct/StructMember.java +@@ -62,6 +62,15 @@ public class StructMember { + StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE); + table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute); + } ++ else if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) && attributes.containsKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE)) { ++ StructLocalVariableTableAttribute lvtt = (StructLocalVariableTableAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE); ++ ((StructLocalVariableTableAttribute)attribute).addLocalVariableTable(lvtt); ++ attributes.addWithKey(attribute, attribute.getName()); ++ } ++ else if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.equals(name) && attributes.containsKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE)) { ++ StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE); ++ table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute); ++ } + else { + attributes.addWithKey(attribute, attribute.getName()); + } +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0009-Rework-of-Generics-system-for-better-output.patch b/FernFlower-Patches/0009-Rework-of-Generics-system-for-better-output.patch deleted file mode 100644 index 79bb0ea..0000000 --- a/FernFlower-Patches/0009-Rework-of-Generics-system-for-better-output.patch +++ /dev/null @@ -1,3116 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Fri, 14 Apr 2017 17:09:41 -0700 -Subject: [PATCH] Rework of Generics system for better output - - -diff --git a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java -index 4c4916e4cc5ccdd06dd4138dae54c31fb7f3bd34..decfe747ba2ab3643209987294ef7bcbbfa15e1b 100644 ---- a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java -+++ b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java -@@ -34,7 +34,7 @@ public final class ClassReference14Processor { - invFor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;")); - invFor.setStatic(true); - invFor.setParameters(Collections.singletonList(new VarExprent(0, VarType.VARTYPE_STRING, null))); -- BODY_EXPR = new ExitExprent(ExitExprent.EXIT_RETURN, invFor, VarType.VARTYPE_CLASS, null); -+ BODY_EXPR = new ExitExprent(ExitExprent.EXIT_RETURN, invFor, VarType.VARTYPE_CLASS, null, null); - - InvocationExprent ctor = new InvocationExprent(); - ctor.setName(CodeConstants.INIT_NAME); -@@ -52,7 +52,7 @@ public final class ClassReference14Processor { - invCause.setInstance(newExpr); - invCause.setParameters( - Collections.singletonList(new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null))); -- HANDLER_EXPR = new ExitExprent(ExitExprent.EXIT_THROW, invCause, null, null); -+ HANDLER_EXPR = new ExitExprent(ExitExprent.EXIT_THROW, invCause, null, null, null); - } - - public static void processClassReferences(ClassNode node) { -@@ -235,4 +235,4 @@ public final class ClassReference14Processor { - - return null; - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java -index 9b4e9fb3ab0a2f54c124c8a4c3943e6d7a5d01d2..31236841f1b4bf4f452f30d6b95f21fcc99ec5b9 100644 ---- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java -+++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java -@@ -371,9 +371,14 @@ public class ClassWriter { - - List typeAnnotations = TypeAnnotation.listFrom(cl); - -- GenericClassDescriptor descriptor = getGenericClassDescriptor(cl); -+ GenericClassDescriptor descriptor = cl.getSignature(); - if (descriptor != null && !descriptor.fparameters.isEmpty()) { -- appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds, typeAnnotations); -+ DecompilerContext.setProperty(DecompilerContext.IN_CLASS_TYPE_PARAMS, "1"); -+ try { -+ appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds, typeAnnotations); -+ } finally { -+ DecompilerContext.setProperty(DecompilerContext.IN_CLASS_TYPE_PARAMS, "0"); -+ } - } - - if (components != null) { -@@ -396,15 +401,7 @@ public class ClassWriter { - List extendsTypeAnnotations = TargetInfo.SupertypeTarget.extractExtends(typeAnnotations); - if (!VarType.VARTYPE_OBJECT.equals(supertype)) { - buffer.append("extends "); -- if (descriptor != null) { -- buffer.append(GenericMain.getGenericCastTypeName( -- descriptor.superclass, -- TypeAnnotationWriteHelper.create(extendsTypeAnnotations)) -- ); -- } -- else { -- buffer.append(ExprProcessor.getCastTypeName(supertype, TypeAnnotationWriteHelper.create(extendsTypeAnnotations))); -- } -+ buffer.append(ExprProcessor.getCastTypeName(descriptor == null ? supertype : descriptor.superclass, TypeAnnotationWriteHelper.create(extendsTypeAnnotations))); - buffer.append(' '); - } - } -@@ -418,18 +415,7 @@ public class ClassWriter { - buffer.append(", "); - } - List superTypeAnnotations = TargetInfo.SupertypeTarget.extract(typeAnnotations, i); -- if (descriptor != null) { -- buffer.append(GenericMain.getGenericCastTypeName( -- descriptor.superinterfaces.get(i), -- TypeAnnotationWriteHelper.create(superTypeAnnotations)) -- ); -- } -- else { -- buffer.append(ExprProcessor.getCastTypeName( -- new VarType(cl.getInterface(i), true), -- TypeAnnotationWriteHelper.create(superTypeAnnotations)) -- ); -- } -+ buffer.append(ExprProcessor.getCastTypeName(descriptor == null ? new VarType(cl.getInterface(i), true) : descriptor.superinterfaces.get(i), TypeAnnotationWriteHelper.create(superTypeAnnotations))); - } - buffer.append(' '); - } -@@ -491,12 +477,7 @@ public class ClassWriter { - final List typeAnnotations = TypeAnnotation.listFrom(fd); - - if (!isEnum) { -- if (descriptor != null) { -- buffer.append(GenericMain.getGenericCastTypeName(descriptor.type, TypeAnnotationWriteHelper.create(typeAnnotations))); -- } -- else { -- buffer.append(ExprProcessor.getCastTypeName(fieldType, TypeAnnotationWriteHelper.create(typeAnnotations))); -- } -+ buffer.append(ExprProcessor.getCastTypeName(descriptor == null ? fieldType : descriptor.type, TypeAnnotationWriteHelper.create(typeAnnotations))); - buffer.append(' '); - } - -@@ -524,8 +505,8 @@ public class ClassWriter { - ((ConstExprent) initializer).adjustConstType(fieldType); - } - -- // FIXME: special case field initializer. Can map to more than one method (constructor) and bytecode instruction -- buffer.append(initializer.toJava(indent, tracer)); -+ // FIXME: special case field initializer. Can map to more than one method (constructor) and bytecode instruction. -+ ExprProcessor.getCastedExprent(initializer, descriptor == null ? fieldType : descriptor.type, buffer, indent, false, tracer); - } - } - else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) { -@@ -638,7 +619,7 @@ public class ClassWriter { - boolean isDeprecated = mt.hasAttribute(StructGeneralAttribute.ATTRIBUTE_DEPRECATED); - boolean clInit = false, dInit = false; - -- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt, node); - - int flags = mt.getAccessFlags(); - if ((flags & CodeConstants.ACC_NATIVE) != 0) { -@@ -666,25 +647,7 @@ public class ClassWriter { - appendComment(buffer, "bridge method", indent); - } - -- GenericMethodDescriptor descriptor = null; -- if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -- StructGenericSignatureAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE); -- if (attr != null) { -- descriptor = GenericMain.parseMethodSignature(attr.getSignature()); -- if (descriptor != null) { -- long actualParams = md.params.length; -- List mask = methodWrapper.synthParameters; -- if (mask != null) { -- actualParams = mask.stream().filter(Objects::isNull).count(); -- } -- if (actualParams != descriptor.parameterTypes.size()) { -- String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor() + " in " + cl.qualifiedName; -- DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); -- descriptor = null; -- } -- } -- } -- } -+ GenericMethodDescriptor descriptor = mt.getSignature(); - appendAnnotations(buffer, indent, mt); - - buffer.appendIndent(indent); -@@ -726,12 +689,7 @@ public class ClassWriter { - if (init) { - emptyTypeAnnotations.forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); - } else { -- if (descriptor != null) { -- buffer.append(GenericMain.getGenericCastTypeName(descriptor.returnType, TypeAnnotationWriteHelper.create(emptyTypeAnnotations))); -- } -- else { -- buffer.append(ExprProcessor.getCastTypeName(md.ret, TypeAnnotationWriteHelper.create(emptyTypeAnnotations))); -- } -+ buffer.append(ExprProcessor.getCastTypeName(descriptor == null ? md.ret : descriptor.returnType, TypeAnnotationWriteHelper.create(emptyTypeAnnotations))); - buffer.append(' '); - } - -@@ -748,7 +706,12 @@ public class ClassWriter { - } - - int index = methodWrapper.varproc.getFirstParameterVarIndex(); -+ boolean hasDescriptor = descriptor != null; -+ //mask should now have the Outer.this in it... so this *shouldn't* be nessasary. -+ //if (init && !isEnum && ((node.access & CodeConstants.ACC_STATIC) == 0) && node.type == ClassNode.CLASS_MEMBER) -+ // index++; - for (int i = methodWrapper.varproc.getFirstParameterPosition(); i < md.params.length; i++) { -+ VarType parameterType = hasDescriptor && !descriptor.parameterTypes.isEmpty() ? descriptor.parameterTypes.get(paramCount) : md.params[i]; - if (mask == null || mask.get(i) == null) { - if (paramCount > 0) { - buffer.append(", "); -@@ -765,23 +728,12 @@ public class ClassWriter { - } - - String typeName; -- boolean isVarArg = i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS); - List typeParamAnnotations = TargetInfo.FormalParameterTarget.extract(typeAnnotations, i); -- if (paramType instanceof GenericType genParamType) { -- isVarArg &= genParamType.getArrayDim() > 0; -- if (isVarArg) { -- genParamType = genParamType.decreaseArrayDim(); -- } -- typeName = GenericMain.getGenericCastTypeName(genParamType, TypeAnnotationWriteHelper.create(typeParamAnnotations)); -- } -- else { -- VarType varParamType = (VarType) paramType; -- isVarArg &= varParamType.getArrayDim() > 0; -- if (isVarArg) { -- varParamType = varParamType.decreaseArrayDim(); -- } -- typeName = ExprProcessor.getCastTypeName(varParamType, TypeAnnotationWriteHelper.create(typeParamAnnotations)); -+ boolean isVarArg = i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.getArrayDim() > 0; -+ if (isVarArg) { -+ parameterType = parameterType.decreaseArrayDim(); - } -+ typeName = ExprProcessor.getCastTypeName(parameterType, TypeAnnotationWriteHelper.create(typeParamAnnotations)); - - if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) && - DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) { -@@ -800,7 +752,7 @@ public class ClassWriter { - paramCount++; - } - -- index += md.params[i].getStackSize(); -+ index += parameterType.getStackSize(); - } - - buffer.append(')'); -@@ -810,19 +762,14 @@ public class ClassWriter { - throwsExceptions = true; - buffer.append(" throws "); - -+ boolean useDescriptor = hasDescriptor && !descriptor.exceptionTypes.isEmpty(); - for (int i = 0; i < attr.getThrowsExceptions().size(); i++) { - if (i > 0) { - buffer.append(", "); - } - TargetInfo.ThrowsTarget.extract(typeAnnotations, i).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); -- if (descriptor != null && !descriptor.exceptionTypes.isEmpty()) { -- GenericType type = descriptor.exceptionTypes.get(i); -- buffer.append(GenericMain.getGenericCastTypeName(type, Collections.emptyList())); -- } -- else { -- VarType type = new VarType(attr.getExcClassname(i, cl.getPool()), true); -- buffer.append(ExprProcessor.getCastTypeName(type, Collections.emptyList())); -- } -+ VarType type = useDescriptor ? descriptor.exceptionTypes.get(i) : new VarType(attr.getExcClassname(i, cl.getPool()), true); -+ buffer.append(ExprProcessor.getCastTypeName(type, Collections.emptyList())); - } - } - } -@@ -1050,7 +997,7 @@ public class ClassWriter { - - final List typeAnnotations = TypeAnnotation.listFrom(cd); - if (descriptor != null) { -- buffer.append(GenericMain.getGenericCastTypeName( -+ buffer.append(ExprProcessor.getCastTypeName( - varArgComponent ? descriptor.type.decreaseArrayDim() : descriptor.type, - TypeAnnotationWriteHelper.create(typeAnnotations) - )); -@@ -1104,14 +1051,7 @@ public class ClassWriter { - private static Map.Entry getFieldTypeData(StructField fd) { - VarType fieldType = new VarType(fd.getDescriptor(), false); - -- GenericFieldDescriptor descriptor = null; -- if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -- StructGenericSignatureAttribute attr = fd.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE); -- if (attr != null) { -- descriptor = GenericMain.parseFieldSignature(attr.getSignature()); -- } -- } -- -+ GenericFieldDescriptor descriptor = fd.getSignature(); - return new AbstractMap.SimpleImmutableEntry<>(fieldType, descriptor); - } - -@@ -1248,22 +1188,11 @@ public class ClassWriter { - } - } - -- public static GenericClassDescriptor getGenericClassDescriptor(StructClass cl) { -- if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -- StructGenericSignatureAttribute attr = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE); -- if (attr != null) { -- return GenericMain.parseClassSignature(attr.getSignature()); -- } -- } -- return null; -- } -- - public static void appendTypeParameters( -- TextBuffer buffer, -- List parameters, -- List> bounds, -- final List typeAnnotations -- ) { -+ TextBuffer buffer, -+ List parameters, -+ List> bounds, -+ final List typeAnnotations) { - buffer.append('<'); - for (int i = 0; i < parameters.size(); i++) { - if (i > 0) { -@@ -1271,15 +1200,15 @@ public class ClassWriter { - } - TargetInfo.TypeParameterTarget.extract(typeAnnotations, i).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); - buffer.append(parameters.get(i)); -- List parameterBounds = bounds.get(i); -+ List parameterBounds = bounds.get(i); - if (parameterBounds.size() > 1 || !"java/lang/Object".equals(parameterBounds.get(0).getValue())) { - buffer.append(" extends "); - TargetInfo.TypeParameterBoundTarget.extract(typeAnnotations, i, 0).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); -- buffer.append(GenericMain.getGenericCastTypeName(parameterBounds.get(0), Collections.emptyList())); -+ buffer.append(ExprProcessor.getCastTypeName(parameterBounds.get(0), Collections.emptyList())); - for (int j = 1; j < parameterBounds.size(); j++) { - buffer.append(" & "); - TargetInfo.TypeParameterBoundTarget.extract(typeAnnotations, i, j).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer)); -- buffer.append(GenericMain.getGenericCastTypeName(parameterBounds.get(j), Collections.emptyList())); -+ buffer.append(ExprProcessor.getCastTypeName(parameterBounds.get(j), Collections.emptyList())); - } - } - } -@@ -1296,4 +1225,4 @@ public class ClassWriter { - } - } - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java -index e2936358fa03746e00e23d30f47351c28124e09f..654d0ddf34821ce4ea800cd5421f6268e2ca3236 100644 ---- a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java -+++ b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java -@@ -18,6 +18,8 @@ public class DecompilerContext { - public static final String CURRENT_CLASS_WRAPPER = "CURRENT_CLASS_WRAPPER"; - public static final String CURRENT_CLASS_NODE = "CURRENT_CLASS_NODE"; - public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER"; -+ public static final String CURRENT_VAR_PROCESSOR = "CURRENT_VAR_PROCESSOR"; -+ public static final String IN_CLASS_TYPE_PARAMS = "IN_CLASS_TYPE_PARAMS"; - - private final Map properties; - private final IFernflowerLogger logger; -@@ -126,4 +128,4 @@ public class DecompilerContext { - public static BytecodeSourceMapper getBytecodeSourceMapper() { - return getCurrentContext().bytecodeSourceMapper; - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/main/Fernflower.java b/src/org/jetbrains/java/decompiler/main/Fernflower.java -index 692c1b622ef7e065c9c970cf0a5289f9ca8869f5..f8c413c7b7302b201a739310677d0103e2878d3e 100644 ---- a/src/org/jetbrains/java/decompiler/main/Fernflower.java -+++ b/src/org/jetbrains/java/decompiler/main/Fernflower.java -@@ -11,6 +11,7 @@ import org.jetbrains.java.decompiler.struct.StructClass; - import org.jetbrains.java.decompiler.struct.StructContext; - import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; - import org.jetbrains.java.decompiler.util.TextBuffer; -+import org.jetbrains.java.decompiler.util.ClasspathScanner; - - import java.io.File; - import java.util.HashMap; -@@ -53,6 +54,15 @@ public class Fernflower implements IDecompiledData { - - DecompilerContext context = new DecompilerContext(properties, logger, structContext, classProcessor, interceptor); - DecompilerContext.setCurrentContext(context); -+ -+ String vendor = System.getProperty("java.vendor", "missing vendor"); -+ String javaVersion = System.getProperty("java.version", "missing java version"); -+ String jvmVersion = System.getProperty("java.vm.version", "missing jvm version"); -+ logger.writeMessage(String.format("JVM info: %s - %s - %s", vendor, javaVersion, jvmVersion), IFernflowerLogger.Severity.INFO); -+ -+ if (DecompilerContext.getOption(IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH)) { -+ ClasspathScanner.addAllClasspath(structContext); -+ } - } - - private static IIdentifierRenamer loadHelper(String className, IFernflowerLogger logger) { -diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -index b509376a6dbc3780f7c14c631bf51b7fc24aa50d..79108dd8772dc9444d66e6ba0cdd7f56ca382fbd 100644 ---- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -+++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -@@ -36,6 +36,7 @@ public interface IFernflowerPreferences { - String VERIFY_ANONYMOUS_CLASSES = "vac"; - - String STANDARDIZE_FLOATING_POINT_NUMBERS = "sfn"; -+ String INCLUDE_ENTIRE_CLASSPATH = "iec"; - - String LOG_LEVEL = "log"; - String MAX_PROCESSING_METHOD = "mpm"; -@@ -84,6 +85,7 @@ public interface IFernflowerPreferences { - defaults.put(VERIFY_ANONYMOUS_CLASSES, "0"); - - defaults.put(STANDARDIZE_FLOATING_POINT_NUMBERS, "1"); -+ defaults.put(INCLUDE_ENTIRE_CLASSPATH, "0"); - - defaults.put(LOG_LEVEL, IFernflowerLogger.Severity.INFO.name()); - defaults.put(MAX_PROCESSING_METHOD, "0"); -diff --git a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -index 33906d3a433e4421bbf41c6aed5ff566a69a904a..c1126a2b7559e2f8a69a54ee0b7db2ceda3d9776 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -@@ -47,7 +47,7 @@ public class ClassWrapper { - for (StructMethod mt : classStruct.getMethods()) { - DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor()); - -- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt, null); - VarProcessor varProc = new VarProcessor(classStruct, mt, md); - DecompilerContext.startMethod(varProc); - -@@ -218,4 +218,4 @@ public class ClassWrapper { - public String toString() { - return classStruct.qualifiedName; - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -index a242aa9e74698b14e20e27d655a3c8ae141ee2f5..e005b2941b4e76b736b8d00905726ac8500c3dc2 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -@@ -29,6 +29,7 @@ import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.Type; - import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; - import org.jetbrains.java.decompiler.util.TextBuffer; - - import java.util.*; -@@ -473,7 +474,7 @@ public class ExprProcessor implements CodeConstants { - exprList.add(new ExitExprent(instr.opcode == opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN, - instr.opcode == opc_return ? null : stack.pop(), - instr.opcode == opc_athrow ? null : methodDescriptor.ret, -- offsets)); -+ offsets, methodDescriptor)); - break; - case opc_monitorenter: - case opc_monitorexit: -@@ -685,7 +686,15 @@ public class ExprProcessor implements CodeConstants { - sb.append("void"); - return sb.toString(); - } -+ else if (tp == CodeConstants.TYPE_GENVAR && type.isGeneric()) { -+ sb.append(type.getValue()); -+ return sb.toString(); -+ } - else if (tp == CodeConstants.TYPE_OBJECT) { -+ if (type.isGeneric()) { -+ ((GenericType)type).appendCastName(sb, typeAnnWriteHelpers); -+ return sb.toString(); -+ } - String ret; - if (getShort) { - ret = DecompilerContext.getImportCollector().getNestedName(type.getValue()); -@@ -736,7 +745,9 @@ public class ExprProcessor implements CodeConstants { - boolean shouldWrite = true; - if (!enclosingClasses.isEmpty() && i != nestedTypes.size() - 1) { - String enclosingType = enclosingClasses.remove(0).simpleName; -- shouldWrite = !nestedType.equals(enclosingType); -+ shouldWrite = !nestedType.equals(enclosingType) -+ // Also write out the enclosing class if we are the outermost, and we're in the type params -+ || enclosingClasses.isEmpty() && DecompilerContext.getOption(DecompilerContext.IN_CLASS_TYPE_PARAMS); - } - if (i == 0) { // first annotation can be written already - if (!sb.toString().isEmpty()) shouldWrite = true; // write if annotation exists -@@ -952,6 +963,8 @@ public class ExprProcessor implements CodeConstants { - tracer.incrementCurrentSourceLine(); - } - -+ expr.getInferredExprType(null); -+ - TextBuffer content = expr.toJava(indent, tracer); - - if (content.length() > 0) { -@@ -1024,7 +1037,7 @@ public class ExprProcessor implements CodeConstants { - } - } - -- VarType rightType = exprent.getExprType(); -+ VarType rightType = exprent.getInferredExprType(leftType); - - boolean cast = - castAlways || -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java -index eb96762fa2174047a3f9dcecfb8c57bf4721c11f..dc3d20eed5ddcac36204fc9ed75d73c53a8c9805 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java -@@ -722,7 +722,7 @@ public class SimplifyExprentsHelper { - Arrays.asList( - statement.getHeadexprent().getCondition(), - ifExit.getValue(), -- elseExit.getValue()), ifHeadExprBytecode), ifExit.getRetType(), ifHeadExprBytecode)); -+ elseExit.getValue()), ifHeadExprBytecode), ifExit.getRetType(), ifHeadExprBytecode, ifExit.getMethodDescriptor())); - statement.setExprents(data); - - StatEdge retEdge = ifStatement.getAllSuccessorEdges().get(0); -@@ -768,4 +768,4 @@ public class SimplifyExprentsHelper { - - return ret; - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -index 06567749310f70d0f3263a9b2bad4588237bdda9..ed470ffbbf57c7aea4e82174a99c8d31a097bc32 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java -@@ -5,7 +5,6 @@ import org.jetbrains.java.decompiler.code.CodeConstants; - import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; - import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; --import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; - import org.jetbrains.java.decompiler.struct.StructField; - import org.jetbrains.java.decompiler.struct.gen.VarType; -@@ -49,6 +48,11 @@ public class AssignmentExprent extends Exprent { - return left.getExprType(); - } - -+ @Override -+ public VarType getInferredExprType(VarType upperBounds) { -+ return left.getInferredExprType(upperBounds); -+ } -+ - @Override - public CheckTypesResult checkExprTypeBounds() { - CheckTypesResult result = new CheckTypesResult(); -@@ -89,8 +93,8 @@ public class AssignmentExprent extends Exprent { - - @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { -- VarType leftType = left.getExprType(); -- VarType rightType = right.getExprType(); -+ VarType leftType = left.getInferredExprType(null); -+ VarType rightType = right.getInferredExprType(leftType); - - boolean fieldInClassInit = false, hiddenField = false; - if (left.type == Exprent.EXPRENT_FIELD) { // first assignment to a final field. Field name without "this" in front of it -@@ -128,14 +132,8 @@ public class AssignmentExprent extends Exprent { - - TextBuffer res = right.toJava(indent, tracer); - -- if (condType == CONDITION_NONE && -- !leftType.isSuperset(rightType) && -- (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.getType() != CodeConstants.TYPE_OBJECT)) { -- if (right.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) { -- res.enclose("(", ")"); -- } -- -- res.prepend("(" + ExprProcessor.getCastTypeName(leftType, Collections.emptyList()) + ")"); -+ if (condType == CONDITION_NONE) { -+ this.wrapInCast(leftType, rightType, res, right.getPrecedence()); - } - - buffer.append(condType == CONDITION_NONE ? " = " : OPERATORS[condType]).append(res); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -index 54f6a306cd28f68879d25a536a1dea7a496a4aa3..9b9a0b4198688968201783fb804130a3312aa522 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java -@@ -10,6 +10,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; - import org.jetbrains.java.decompiler.struct.attr.StructExceptionsAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; -+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; -@@ -28,19 +29,21 @@ public class ExitExprent extends Exprent { - private final int exitType; - private Exprent value; - private final VarType retType; -+ private final MethodDescriptor methodDescriptor; - -- public ExitExprent(int exitType, Exprent value, VarType retType, BitSet bytecodeOffsets) { -+ public ExitExprent(int exitType, Exprent value, VarType retType, BitSet bytecodeOffsets, MethodDescriptor methodDescriptor) { - super(EXPRENT_EXIT); - this.exitType = exitType; - this.value = value; - this.retType = retType; -+ this.methodDescriptor = methodDescriptor; - - addBytecodeOffsets(bytecodeOffsets); - } - - @Override - public Exprent copy() { -- return new ExitExprent(exitType, value == null ? null : value.copy(), retType, bytecode); -+ return new ExitExprent(exitType, value == null ? null : value.copy(), retType, bytecode, methodDescriptor); - } - - @Override -@@ -72,8 +75,12 @@ public class ExitExprent extends Exprent { - TextBuffer buffer = new TextBuffer("return"); - - if (retType.getType() != CodeConstants.TYPE_VOID) { -+ VarType ret = retType; -+ if (methodDescriptor != null && methodDescriptor.genericInfo != null && methodDescriptor.genericInfo.returnType != null) { -+ ret = methodDescriptor.genericInfo.returnType; -+ } - buffer.append(' '); -- ExprProcessor.getCastedExprent(value, retType, buffer, indent, false, tracer); -+ ExprProcessor.getCastedExprent(value, ret, buffer, indent, false, false, false, false, tracer); - } - - return buffer; -@@ -140,6 +147,10 @@ public class ExitExprent extends Exprent { - return retType; - } - -+ public MethodDescriptor getMethodDescriptor() { -+ return this.methodDescriptor; -+ } -+ - @Override - public void getBytecodeRange(BitSet values) { - measureBytecode(values, value); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -index 67fc1f2beab815f0ca07ecf8a34b98fa23344749..33150f76d649f124bc818036b0f7c6331d5e74be 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -@@ -3,13 +3,20 @@ - */ - package org.jetbrains.java.decompiler.modules.decompiler.exps; - -+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; -+import org.jetbrains.java.decompiler.code.CodeConstants; - import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.util.TextBuffer; - import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.main.collectors.CounterContainer; -+import org.jetbrains.java.decompiler.main.rels.MethodWrapper; -+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; - import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; - import org.jetbrains.java.decompiler.struct.match.IMatchable; - import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; -@@ -19,8 +26,10 @@ import java.util.ArrayList; - import java.util.BitSet; - import java.util.Collections; - import java.util.Comparator; -+import java.util.HashMap; - import java.util.HashSet; - import java.util.List; -+import java.util.Map; - import java.util.Map.Entry; - import java.util.Set; - -@@ -61,6 +70,11 @@ public abstract class Exprent implements IMatchable { - return VarType.VARTYPE_VOID; - } - -+ // TODO: This captures the state of upperBound, find a way to do it without modifying state? -+ public VarType getInferredExprType(VarType upperBound) { -+ return getExprType(); -+ } -+ - public int getExprentUse() { - return 0; - } -@@ -184,6 +198,119 @@ public abstract class Exprent implements IMatchable { - return ret; - } - -+ protected VarType gatherGenerics(VarType upperBound, VarType ret, List fparams, List genericArgs) { -+ Map map = new HashMap<>(); -+ -+ // List -> List -+ if (upperBound != null && upperBound.isGeneric() && ret.isGeneric()) { -+ List leftArgs = ((GenericType)upperBound).getArguments(); -+ List rightArgs = ((GenericType)ret).getArguments(); -+ if (leftArgs.size() == rightArgs.size() && rightArgs.size() == fparams.size()) { -+ for (int i = 0; i < leftArgs.size(); i++) { -+ VarType left = leftArgs.get(i); -+ VarType right = rightArgs.get(i); -+ if (left != null && right.getValue().equals(fparams.get(i))) { -+ genericArgs.add(left); -+ map.put(right, left); -+ } else { -+ genericArgs.clear(); -+ map.clear(); -+ break; -+ } -+ } -+ } -+ } -+ -+ return map.isEmpty() ? ret : ret.remap(map); -+ } -+ -+ protected void appendParameters(TextBuffer buf, List genericArgs) { -+ if (genericArgs.isEmpty()) { -+ return; -+ } -+ buf.append("<"); -+ //TODO: Check target output level and use <> operator? -+ for (int i = 0; i < genericArgs.size(); i++) { -+ buf.append(ExprProcessor.getCastTypeName(genericArgs.get(i), Collections.emptyList())); -+ if(i + 1 < genericArgs.size()) { -+ buf.append(", "); -+ } -+ } -+ buf.append(">"); -+ } -+ -+ protected Map> getNamedGenerics() { -+ Map> ret = new HashMap<>(); -+ ClassNode class_ = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); -+ MethodWrapper method = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); -+ -+ //TODO: Loop enclosing classes? -+ GenericClassDescriptor cls = class_ == null ? null : class_.classStruct.getSignature(); -+ if (cls != null) { -+ for (int x = 0; x < cls.fparameters.size(); x++) { -+ ret.put(GenericType.parse("T" + cls.fparameters.get(x) + ";"), cls.fbounds.get(x)); -+ } -+ } -+ -+ //TODO: Loop enclosing method? -+ GenericMethodDescriptor mtd = method == null ? null : method.methodStruct.getSignature(); -+ if (mtd != null) { -+ for (int x = 0; x < mtd.typeParameters.size(); x++) { -+ ret.put(GenericType.parse("T" + mtd.typeParameters.get(x) + ";"), mtd.typeParameterBounds.get(x)); -+ } -+ } -+ -+ return ret; -+ } -+ -+ protected void wrapInCast(VarType left, VarType right, TextBuffer buf, int precedence) { -+ boolean needsCast = !left.isSuperset(right) && (right.equals(VarType.VARTYPE_OBJECT) || left.getType() != CodeConstants.TYPE_OBJECT); -+ -+ if (left != null && left.isGeneric()) { -+ Map> names = this.getNamedGenerics(); -+ int arrayDim = 0; -+ -+ if (left.getArrayDim() == right.getArrayDim()) { -+ arrayDim = left.getArrayDim(); -+ left = left.resizeArrayDim(0); -+ right = right.resizeArrayDim(0); -+ } -+ -+ List types = names.get(right); -+ if (types == null) { -+ types = names.get(left); -+ } -+ -+ if (types != null) { -+ boolean anyMatch = false; //TODO: allMatch instead of anyMatch? -+ for (VarType type : types) { -+ if (type.equals(VarType.VARTYPE_OBJECT) && right.equals(VarType.VARTYPE_OBJECT)) { -+ continue; -+ } -+ anyMatch |= right.getValue() == null /*null const doesn't need cast*/ || DecompilerContext.getStructContext().instanceOf(right.getValue(), type.getValue()); -+ } -+ -+ if (anyMatch) { -+ needsCast = false; -+ } -+ } -+ -+ if (arrayDim != 0) { -+ left = left.resizeArrayDim(arrayDim); -+ } -+ } -+ -+ if (!needsCast) { -+ return; -+ } -+ -+ if (precedence >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) { -+ buf.enclose("(", ")"); -+ } -+ -+ buf.prepend("(" + ExprProcessor.getCastTypeName(left, Collections.emptyList()) + ")"); -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -index 379242393a83c6b3502a88c8d745a5b0bc1b5476..040e5d21985979a9686cb9fee6e3048fe87e5464 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java -@@ -8,6 +8,8 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.main.rels.MethodWrapper; - import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -+import org.jetbrains.java.decompiler.struct.StructClass; -+import org.jetbrains.java.decompiler.struct.StructField; - import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute; - import org.jetbrains.java.decompiler.struct.consts.LinkConstant; - import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; -@@ -20,7 +22,9 @@ import org.jetbrains.java.decompiler.util.TextUtil; - - import java.util.ArrayList; - import java.util.BitSet; -+import java.util.Collections; - import java.util.List; -+import java.util.Map; - import java.util.Objects; - - public class FieldExprent extends Exprent { -@@ -50,6 +54,26 @@ public class FieldExprent extends Exprent { - return descriptor.type; - } - -+ @Override -+ public VarType getInferredExprType(VarType upperBound) { -+ StructClass cl = DecompilerContext.getStructContext().getClass(classname); -+ Map> types = cl == null ? Collections.emptyMap() : cl.getAllGenerics(); -+ -+ StructField ft = null; -+ while(cl != null) { -+ ft = cl.getField(name, descriptor.descriptorString); -+ if (ft != null) -+ break; -+ cl = cl.superClass == null ? null : DecompilerContext.getStructContext().getClass((String)cl.superClass.value); -+ } -+ -+ if (ft != null && ft.getSignature() != null) { -+ return ft.getSignature().type.remap(types.getOrDefault(cl.qualifiedName, Collections.emptyMap())); -+ } -+ -+ return getExprType(); -+ } -+ - @Override - public int getExprentUse() { - return 0; // multiple references to a field considered dangerous in a multithreaded environment, thus no Exprent.MULTIPLE_USES set here -@@ -210,4 +234,4 @@ public class FieldExprent extends Exprent { - - return true; - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index b2b26fb3f8b075182caee14d57b4cc351ffb120a..f18ef04b350a5f6d4599282aef5ea3f6e3dce778 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -@@ -2,6 +2,8 @@ - package org.jetbrains.java.decompiler.modules.decompiler.exps; - - import org.jetbrains.java.decompiler.code.CodeConstants; -+import org.jetbrains.java.decompiler.util.TextBuffer; -+import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; - import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; -@@ -9,7 +11,6 @@ import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.util.ListStack; --import org.jetbrains.java.decompiler.util.TextBuffer; - - import java.util.*; - -@@ -182,6 +183,7 @@ public class FunctionExprent extends Exprent { - private int funcType; - private VarType implicitType; - private final List lstOperands; -+ private boolean needsCast = true; - - public FunctionExprent(int funcType, ListStack stack, BitSet bytecodeOffsets) { - this(funcType, new ArrayList<>(), bytecodeOffsets); -@@ -269,6 +271,46 @@ public class FunctionExprent extends Exprent { - return exprType; - } - -+ @Override -+ public VarType getInferredExprType(VarType upperBound) { -+ if (funcType == FUNCTION_CAST) { -+ this.needsCast = true; -+ VarType right = lstOperands.get(0).getInferredExprType(upperBound); -+ VarType cast = lstOperands.get(1).getExprType(); -+ -+ if (upperBound != null && upperBound.isGeneric()) { -+ Map> names = this.getNamedGenerics(); -+ int arrayDim = 0; -+ -+ if (upperBound.getArrayDim() == right.getArrayDim()) { -+ arrayDim = upperBound.getArrayDim(); -+ upperBound = upperBound.resizeArrayDim(0); -+ right = right.resizeArrayDim(0); -+ } -+ -+ List types = names.get(right); -+ if (types == null) { -+ types = names.get(upperBound); -+ } -+ -+ if (types != null) { -+ boolean anyMatch = false; //TODO: allMatch instead of anyMatch? -+ for (VarType type : types) { -+ anyMatch |= DecompilerContext.getStructContext().instanceOf(type.getValue(), cast.getValue()); -+ } -+ if (anyMatch) { -+ this.needsCast = false; -+ } -+ } -+ } -+ else { //TODO: Capture generics to make cast better? -+ this.needsCast = right.getType() == CodeConstants.TYPE_NULL || !DecompilerContext.getStructContext().instanceOf(right.getValue(), cast.getValue()); -+ } -+ } -+ return getExprType(); -+ } -+ -+ - @Override - public int getExprentUse() { - if (funcType >= FUNCTION_IMM && funcType <= FUNCTION_PPI) { -@@ -438,8 +480,12 @@ public class FunctionExprent extends Exprent { - case FUNCTION_BIT_NOT -> wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("~"); - case FUNCTION_BOOL_NOT -> wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("!"); - case FUNCTION_NEG -> wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("-"); -- case FUNCTION_CAST -> lstOperands.get(1).toJava(indent, tracer).enclose("(", ")") -- .append(wrapOperandString(lstOperands.get(0), true, indent, tracer)); -+ case FUNCTION_CAST -> { -+ if (!needsCast) { -+ yield lstOperands.get(0).toJava(indent, tracer); -+ } -+ yield lstOperands.get(1).toJava(indent, tracer).enclose("(", ")").append(wrapOperandString(lstOperands.get(0), true, indent, tracer)); -+ } - case FUNCTION_ARRAY_LENGTH -> { - Exprent arr = lstOperands.get(0); - TextBuffer res = wrapOperandString(arr, false, indent, tracer); -@@ -570,7 +616,7 @@ public class FunctionExprent extends Exprent { - measureBytecode(values, lstOperands); - measureBytecode(values); - } -- -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -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 6776219b98b6b244bb9deda8cffc7b8fc63e4ac6..2d8abaec74b301f76fcd4149600c1da72cc9b6c4 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -@@ -19,6 +19,8 @@ import org.jetbrains.java.decompiler.struct.consts.LinkConstant; - import org.jetbrains.java.decompiler.struct.consts.PooledConstant; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; - import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue; -@@ -56,6 +58,7 @@ public class InvocationExprent extends Exprent { - private int invocationType = INVOKE_VIRTUAL; - private List parameters = new ArrayList<>(); - private List bootstrapArguments; -+ private List genericArgs = new ArrayList<>(); - - public InvocationExprent() { - super(EXPRENT_INVOCATION); -@@ -158,6 +161,55 @@ public class InvocationExprent extends Exprent { - return descriptor.ret; - } - -+ -+ @Override -+ public VarType getInferredExprType(VarType upperBound) { -+ List matches = getMatchedDescriptors(); -+ StructMethod desc = null; -+ if(matches.size() == 1) { -+ desc = matches.get(0); -+ } -+ -+ genericArgs.clear(); -+ -+ if (desc != null && desc.getSignature() != null) { -+ VarType ret = desc.getSignature().returnType; -+ -+ if (instance != null) { -+ VarType instType = instance.getInferredExprType(upperBound); -+ -+ if (instType.isGeneric()) { -+ StructClass cls = DecompilerContext.getStructContext().getClass(instType.getValue()); -+ -+ if (cls != null && cls.getSignature() != null) { -+ Map map = new HashMap<>(); -+ GenericType ginstance = (GenericType)instType; -+ -+ if (cls.getSignature().fparameters.size() == ginstance.getArguments().size()) { -+ for (int x = 0; x < ginstance.getArguments().size(); x++) { -+ if (ginstance.getArguments().get(x) != null) { //TODO: Wildcards are null arguments.. look into fixing things? -+ map.put(GenericType.parse("T" + cls.getSignature().fparameters.get(x) + ";"), ginstance.getArguments().get(x)); -+ } -+ } -+ } -+ -+ if (!map.isEmpty()) { -+ ret = ret.remap(map); -+ } -+ } -+ } -+ } -+ -+ VarType _new = this.gatherGenerics(upperBound, ret, desc.getSignature().typeParameters, genericArgs); -+ if (desc.getSignature().returnType != _new) { -+ return _new; -+ } -+ } -+ -+ return getExprType(); -+ } -+ -+ - @Override - public CheckTypesResult checkExprTypeBounds() { - CheckTypesResult result = new CheckTypesResult(); -@@ -290,6 +342,7 @@ public class InvocationExprent extends Exprent { - - if (buf.length() > 0) { - buf.append("."); -+ this.appendParameters(buf, genericArgs); - } - - buf.append(name); -@@ -324,8 +377,30 @@ public class InvocationExprent extends Exprent { - isEnum = newNode.classStruct.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); - } - } -+ List matches = getMatchedDescriptors(); -+ BitSet setAmbiguousParameters = getAmbiguousParameters(matches); -+ StructMethod desc = null; -+ if(matches.size() == 1) { -+ desc = matches.get(0); -+ } - -- BitSet setAmbiguousParameters = getAmbiguousParameters(); -+ StructClass cl = DecompilerContext.getStructContext().getClass(className); -+ Map genArgs = new HashMap<>(); -+ -+ // building generic info from the instance -+ VarType inferred = instance == null ? null : instance.getInferredExprType(null); -+ if (cl != null && cl.getSignature() != null && instance != null && inferred.isGeneric()) { -+ GenericType genType = (GenericType)inferred; -+ if (genType.getArguments().size() == cl.getSignature().fparameters.size()) { -+ for (int i = 0; i < cl.getSignature().fparameters.size(); i++) { -+ VarType from = GenericType.parse("T" + cl.getSignature().fparameters.get(i) + ";"); -+ VarType to = genType.getArguments().get(i); -+ if (from != null && to != null) { -+ genArgs.put(from, to); -+ } -+ } -+ } -+ } - - // omit 'new Type[] {}' for the last parameter of a vararg method call - if (parameters.size() == descriptor.params.length && isVarArgCall()) { -@@ -341,6 +416,34 @@ public class InvocationExprent extends Exprent { - if (mask == null || mask.get(i) == null) { - TextBuffer buff = new TextBuffer(); - boolean ambiguous = setAmbiguousParameters.get(i); -+ /* -+ VarType type = descriptor.params[i]; -+ -+ // using info from the generic signature -+ if (desc != null && desc.getSignature() != null && desc.getSignature().params.size() == lstParameters.size()) { -+ type = desc.getSignature().params.get(i); -+ } -+ -+ // applying generic info from the signature -+ VarType remappedType = type.remap(genArgs); -+ if(type != remappedType) { -+ type = remappedType; -+ } -+ else if (desc != null && desc.getSignature() != null && genericArgs.size() != 0) { // and from the inferred generic arguments -+ Map genMap = new HashMap(); -+ for (int j = 0; j < genericArgs.size(); j++) { -+ VarType from = GenericType.parse("T" + desc.getSignature().fparameters.get(j) + ";"); -+ VarType to = genericArgs.get(j); -+ genMap.put(from, to); -+ } -+ } -+ -+ // not passing it along if what we get back is more specific -+ VarType exprType = lstParameters.get(i).getInferredExprType(type); -+ if (exprType != null && type != null && type.type == CodeConstants.TYPE_GENVAR) { -+ //type = exprType; -+ } -+ */ - - // 'byte' and 'short' literals need an explicit narrowing type cast when used as a parameter - ExprProcessor.getCastedExprent(parameters.get(i), descriptor.params[i], buff, indent, true, ambiguous, true, true, tracer); -@@ -447,12 +550,11 @@ public class InvocationExprent extends Exprent { - return !isStatic && parameters.size() == 0 && className.equals(UNBOXING_METHODS.get(name)); - } - -- private BitSet getAmbiguousParameters() { -+ private List getMatchedDescriptors() { -+ List matches = new ArrayList<>(); - StructClass cl = DecompilerContext.getStructContext().getClass(className); -- if (cl == null) return EMPTY_BIT_SET; -+ if (cl == null) return matches; - -- // check number of matches -- List matches = new ArrayList<>(); - nextMethod: - for (StructMethod mt : cl.getMethods()) { - if (name.equals(mt.getName())) { -@@ -463,11 +565,19 @@ public class InvocationExprent extends Exprent { - continue nextMethod; - } - } -- matches.add(md); -+ matches.add(mt); - } - } - } -- if (matches.size() == 1) return EMPTY_BIT_SET; -+ -+ return matches; -+ } -+ -+ private BitSet getAmbiguousParameters(List matches) { -+ StructClass cl = DecompilerContext.getStructContext().getClass(className); -+ if (cl == null || matches.size() == 1) { -+ return EMPTY_BIT_SET; -+ } - - // check if a call is unambiguous - StructMethod mt = cl.getMethod(InterpreterUtil.makeUniqueKey(name, stringDescriptor)); -@@ -489,7 +599,14 @@ public class InvocationExprent extends Exprent { - BitSet ambiguous = new BitSet(descriptor.params.length); - for (int i = 0; i < descriptor.params.length; i++) { - VarType paramType = descriptor.params[i]; -- for (MethodDescriptor md : matches) { -+ for (StructMethod mtt : matches) { -+ -+ GenericMethodDescriptor gen = mtt.getSignature(); //TODO: Find synthetic flags for params, as Enum generic signatures do no contain the String,int params -+ if (gen != null && gen.parameterTypes.size() > i && gen.parameterTypes.get(i).isGeneric()) { -+ break; -+ } -+ -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mtt.getDescriptor()); - if (!paramType.equals(md.params[i])) { - ambiguous.set(i); - break; -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -index c47ae33d7d62a5049a89bb586032fc18bdc80173..2405fe08663102626f6ab007ccf5ee6c0e8922ea 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java -@@ -14,7 +14,6 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; - import org.jetbrains.java.decompiler.struct.StructClass; - import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor; --import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; - import org.jetbrains.java.decompiler.util.ListStack; - import org.jetbrains.java.decompiler.util.TextBuffer; - -@@ -30,6 +29,7 @@ public class NewExprent extends Exprent { - private boolean anonymous; - private boolean lambda; - private boolean enumConst; -+ private List genericArgs = new ArrayList<>(); - - public NewExprent(VarType newType, ListStack stack, int arrayDim, BitSet bytecodeOffsets) { - this(newType, getDimensions(arrayDim, stack), bytecodeOffsets); -@@ -68,6 +68,24 @@ public class NewExprent extends Exprent { - return anonymous ? DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.getValue()).anonymousClassType : newType; - } - -+ @Override -+ public VarType getInferredExprType(VarType upperBound) { -+ genericArgs.clear(); -+ if (newType.getType() == CodeConstants.TYPE_OBJECT && newType.getArrayDim() == 0) { -+ StructClass node = DecompilerContext.getStructContext().getClass(newType.getValue()); -+ -+ if (node != null && node.getSignature() != null) { -+ GenericClassDescriptor sig = node.getSignature(); -+ VarType _new = this.gatherGenerics(upperBound, sig.genericType, sig.fparameters, genericArgs); -+ if (sig.genericType != _new) { -+ return _new; -+ } -+ } -+ } -+ -+ return getExprType(); -+ } -+ - @Override - public CheckTypesResult checkExprTypeBounds() { - CheckTypesResult result = new CheckTypesResult(); -@@ -169,17 +187,17 @@ public class NewExprent extends Exprent { - } - } - -- GenericClassDescriptor descriptor = ClassWriter.getGenericClassDescriptor(child.classStruct); -+ GenericClassDescriptor descriptor = child.getWrapper().getClassStruct().getSignature(); - if (descriptor != null) { - if (descriptor.superinterfaces.isEmpty()) { -- buf.append(GenericMain.getGenericCastTypeName(descriptor.superclass, Collections.emptyList())); -+ buf.append(ExprProcessor.getCastTypeName(descriptor.superclass, Collections.emptyList())); - } - else { - if (descriptor.superinterfaces.size() > 1 && !lambda) { - DecompilerContext.getLogger().writeMessage("Inconsistent anonymous class signature: " + child.classStruct.qualifiedName, - IFernflowerLogger.Severity.WARN); - } -- buf.append(GenericMain.getGenericCastTypeName(descriptor.superinterfaces.get(0), Collections.emptyList())); -+ buf.append(ExprProcessor.getCastTypeName(descriptor.superinterfaces.get(0), Collections.emptyList())); - } - } - else { -@@ -188,6 +206,7 @@ public class NewExprent extends Exprent { - } - } - -+ appendParameters(buf, genericArgs); - buf.append('('); - - if (!lambda && constructor != null) { -@@ -279,6 +298,7 @@ public class NewExprent extends Exprent { - - int start = enumConst ? 2 : 0; - if (!enumConst || start < parameters.size()) { -+ appendParameters(buf, genericArgs); - buf.append('('); - - boolean firstParam = true; -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -index 8abfd33115391d24d08d349af9a5b64b1d75c1bf..bbe17e0b2c4dcb7214e0c94cc34156e5c9f233a0 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java -@@ -20,6 +20,7 @@ import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTypeTableAtt - import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor; - import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; - import org.jetbrains.java.decompiler.struct.match.MatchEngine; - import org.jetbrains.java.decompiler.struct.match.MatchNode; - import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue; -@@ -62,6 +63,22 @@ public class VarExprent extends Exprent { - return getVarType(); - } - -+ @Override -+ public VarType getInferredExprType(VarType upperBound) { -+ if (lvt != null && lvt.getSignature() != null) { -+ // TODO; figure out why it's crashing, ugly fix for now -+ try { -+ return GenericType.parse(lvt.getSignature()); -+ } catch (StringIndexOutOfBoundsException ex) { -+ ex.printStackTrace(); -+ } -+ } -+ else if (lvt != null) { -+ return lvt.getVarType(); -+ } -+ return getVarType(); -+ } -+ - @Override - public int getExprentUse() { - return Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE; -@@ -139,7 +156,7 @@ public class VarExprent extends Exprent { - if (lvt.getSignature() != null) { - GenericFieldDescriptor descriptor = GenericMain.parseFieldSignature(lvt.getSignature()); - if (descriptor != null) { -- buffer.append(GenericMain.getGenericCastTypeName(descriptor.type, Collections.emptyList())); -+ buffer.append(ExprProcessor.getCastTypeName(descriptor.type, Collections.emptyList())); - return; - } - } -@@ -165,7 +182,7 @@ public class VarExprent extends Exprent { - if (signature != null) { - GenericFieldDescriptor descriptor = GenericMain.parseFieldSignature(signature); - if (descriptor != null) { -- buffer.append(GenericMain.getGenericCastTypeName(descriptor.type, Collections.emptyList())); -+ buffer.append(ExprProcessor.getCastTypeName(descriptor.type, Collections.emptyList())); - return; - } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java -index 018d3fbdf53036db90b6c64e872098542133b630..d58218e0baa786456f15a14ef23a8d82d466ba18 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java -@@ -107,6 +107,7 @@ public final class DoStatement extends Statement { - } - case FOREACH -> { - buf.appendIndent(indent).append("for(").append(initExprent.get(0).toJava(indent, tracer)); -+ incExprent.get(0).getInferredExprType(null); //TODO: Find a better then null? For now just calls it to clear casts if needed - buf.append(" : ").append(incExprent.get(0).toJava(indent, tracer)).append(") {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -index f2c0589344ed69685dd3103d060109c700c7ee41..f9a7e55c108959b9696cb52cfd91aee341e40b06 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -@@ -24,7 +24,6 @@ import org.jetbrains.java.decompiler.struct.StructMethod; - import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute.LocalVariable; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.VarType; --import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; - import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; - - import java.util.*; -@@ -986,7 +985,7 @@ public class VarDefinitionHelper { - - private VarInfo(LocalVariable lvt, VarType type) { - if (lvt != null && lvt.getSignature() != null) -- this.cast = GenericMain.getGenericCastTypeName(new GenericType(lvt.getSignature()), Collections.emptyList()); -+ this.cast = ExprProcessor.getCastTypeName(GenericType.parse(lvt.getSignature()), true, Collections.emptyList()); - else if (lvt != null) - this.cast = ExprProcessor.getCastTypeName(lvt.getVarType(), false, Collections.emptyList()); - else if (type != null) -diff --git a/src/org/jetbrains/java/decompiler/struct/StructClass.java b/src/org/jetbrains/java/decompiler/struct/StructClass.java -index 0b4275f57e3092623c4e462b032b418cf2bdd84b..bead2d172e27075e63f6977562988041a96a4371 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructClass.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructClass.java -@@ -2,20 +2,32 @@ - package org.jetbrains.java.decompiler.struct; - - import org.jetbrains.java.decompiler.code.CodeConstants; -+import org.jetbrains.java.decompiler.main.DecompilerContext; -+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; -+import org.jetbrains.java.decompiler.struct.attr.StructGenericSignatureAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructPermittedSubclassesAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructRecordAttribute; - import org.jetbrains.java.decompiler.struct.consts.ConstantPool; - import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant; - import org.jetbrains.java.decompiler.struct.gen.Type; -+import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; - import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; - import org.jetbrains.java.decompiler.util.DataInputFullStream; - import org.jetbrains.java.decompiler.util.InterpreterUtil; - import org.jetbrains.java.decompiler.util.VBStyleCollection; - - import java.io.IOException; -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.HashSet; - import java.util.List; - import java.util.Map; -+import java.util.Map.Entry; -+import java.util.Set; - - /* - class_file { -@@ -76,8 +88,16 @@ public class StructClass extends StructMember { - - Map attributes = readAttributes(in, pool); - -+ GenericClassDescriptor signature = null; -+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -+ StructGenericSignatureAttribute signatureAttr = (StructGenericSignatureAttribute)attributes.get(StructGeneralAttribute.ATTRIBUTE_SIGNATURE.name); -+ if (signatureAttr != null) { -+ signature = GenericMain.parseClassSignature(qualifiedName, signatureAttr.getSignature()); -+ } -+ } -+ - StructClass cl = new StructClass( -- accessFlags, attributes, qualifiedName, superClass, own, loader, minorVersion, majorVersion, interfaces, interfaceNames, fields, methods); -+ accessFlags, attributes, qualifiedName, superClass, own, loader, minorVersion, majorVersion, interfaces, interfaceNames, fields, methods, signature); - if (loader == null) cl.pool = pool; - return cl; - } -@@ -92,6 +112,7 @@ public class StructClass extends StructMember { - private final String[] interfaceNames; - private final VBStyleCollection fields; - private final VBStyleCollection methods; -+ private final GenericClassDescriptor signature; - - private ConstantPool pool; - -@@ -106,7 +127,8 @@ public class StructClass extends StructMember { - int[] interfaces, - String[] interfaceNames, - VBStyleCollection fields, -- VBStyleCollection methods) { -+ VBStyleCollection methods, -+ GenericClassDescriptor signature) { - super(accessFlags, attributes); - this.qualifiedName = qualifiedName; - this.superClass = superClass; -@@ -118,6 +140,7 @@ public class StructClass extends StructMember { - this.interfaceNames = interfaceNames; - this.fields = fields; - this.methods = methods; -+ this.signature = signature; - } - - public boolean hasField(String name, String descriptor) { -@@ -242,4 +265,106 @@ public class StructClass extends StructMember { - protected Type getType() { - return null; - } -+ -+ public GenericClassDescriptor getSignature() { -+ return signature; -+ } -+ -+ private Map getGenericMap(VarType type) { -+ if (this.signature == null || type == null || !type.isGeneric()) { -+ return Collections.emptyMap(); -+ } -+ GenericType gtype = (GenericType)type; -+ if (gtype.getArguments().size() != this.signature.fparameters.size()) { //Invalid instance type? -+ return Collections.emptyMap(); -+ } -+ -+ Map ret = new HashMap<>(); -+ for (int x = 0; x < this.signature.fparameters.size(); x++) { -+ VarType var = gtype.getArguments().get(x); -+ if (var != null) { -+ ret.put(GenericType.parse("T" + this.signature.fparameters.get(x) + ";"), var); -+ } -+ } -+ return ret; -+ } -+ -+ private Map> genericHiarachy; -+ public Map> getAllGenerics() { -+ if (genericHiarachy != null) { -+ return genericHiarachy; -+ } -+ -+ Map> ret = new HashMap<>(); -+ if (this.signature != null && !this.signature.fparameters.isEmpty()) { -+ Map mine = new HashMap<>(); -+ for (String par : this.signature.fparameters) { -+ VarType type = GenericType.parse("T" + par + ";"); -+ mine.put(type, type); -+ } -+ ret.put(this.qualifiedName, mine); -+ } -+ -+ Set visited = new HashSet<>(); //Is there a better way? Is the signature forced to contain all interfaces? -+ if (this.signature != null) { -+ for (VarType intf : this.signature.superinterfaces) { -+ visited.add(intf.getValue()); -+ -+ StructClass cls = DecompilerContext.getStructContext().getClass(intf.getValue()); -+ if (cls != null) { -+ Map sig = cls.getGenericMap(intf); -+ -+ for (Entry> e : cls.getAllGenerics().entrySet()) { -+ if (e.getValue().isEmpty()) { -+ ret.put(e.getKey(), e.getValue()); -+ } -+ else { -+ Map sub = new HashMap<>(); -+ for (Entry e2 : e.getValue().entrySet()) { -+ sub.put(e2.getKey(), sig.getOrDefault(e2.getValue(), e2.getValue())); -+ } -+ ret.put(e.getKey(), sub); -+ } -+ } -+ } -+ } -+ } -+ -+ for (String intf : this.interfaceNames) { -+ if (visited.contains(intf)) { -+ continue; -+ } -+ StructClass cls = DecompilerContext.getStructContext().getClass(intf); -+ if (cls != null) { -+ ret.putAll(cls.getAllGenerics()); -+ } -+ } -+ -+ if (this.superClass != null) { -+ StructClass cls = DecompilerContext.getStructContext().getClass((String)this.superClass.value); -+ if (cls != null) { -+ Map sig = this.signature == null ? Collections.emptyMap() : cls.getGenericMap(this.signature.superclass); -+ if (sig.isEmpty()) { -+ ret.putAll(cls.getAllGenerics()); -+ } -+ else { -+ for (Entry> e : cls.getAllGenerics().entrySet()) { -+ if (e.getValue().isEmpty()) { -+ ret.put(e.getKey(), e.getValue()); -+ } -+ else { -+ Map sub = new HashMap<>(); -+ for (Entry e2 : e.getValue().entrySet()) { -+ sub.put(e2.getKey(), sig.getOrDefault(e2.getValue(), e2.getValue())); -+ } -+ ret.put(e.getKey(), sub); -+ } -+ } -+ } -+ } -+ } -+ -+ this.genericHiarachy = ret.isEmpty() ? Collections.emptyMap() : ret; -+ return this.genericHiarachy; -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/StructContext.java b/src/org/jetbrains/java/decompiler/struct/StructContext.java -index 2f55882afdd1dd1b9960aa0c2a007069204797e9..85fc95d87bd7e672613f6c1beb75b2d56d1d759f 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructContext.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructContext.java -@@ -161,6 +161,19 @@ public class StructContext { - } - } - -+ public void addData(String path, String cls, byte[] data, boolean isOwn) throws IOException { -+ ContextUnit unit = units.get(path); -+ if (unit == null) { -+ unit = new ContextUnit(ContextUnit.TYPE_FOLDER, path, cls, isOwn, saver, decompiledData); -+ units.put(path, unit); -+ } -+ -+ StructClass cl = StructClass.create(new DataInputFullStream(data), isOwn, loader); -+ classes.put(cl.qualifiedName, cl); -+ unit.addClass(cl, cls); -+ loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(path, cls, data)); -+ } -+ - public Map getClasses() { - return classes; - } -diff --git a/src/org/jetbrains/java/decompiler/struct/StructField.java b/src/org/jetbrains/java/decompiler/struct/StructField.java -index 0d6df7e05b9b385e743c85261b77215314167989..da073261717d3583fc91b6c9c30351ce439da80c 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructField.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructField.java -@@ -1,10 +1,15 @@ - // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. - package org.jetbrains.java.decompiler.struct; - -+import org.jetbrains.java.decompiler.main.DecompilerContext; -+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; -+import org.jetbrains.java.decompiler.struct.attr.StructGenericSignatureAttribute; - import org.jetbrains.java.decompiler.struct.consts.ConstantPool; - import org.jetbrains.java.decompiler.struct.gen.Type; - import org.jetbrains.java.decompiler.struct.gen.VarType; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; - import org.jetbrains.java.decompiler.util.DataInputFullStream; - - import java.io.IOException; -@@ -28,17 +33,30 @@ public class StructField extends StructMember { - String[] values = pool.getClassElement(ConstantPool.FIELD, clQualifiedName, nameIndex, descriptorIndex); - - Map attributes = readAttributes(in, pool); -+ GenericFieldDescriptor signature = null; -+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -+ StructGenericSignatureAttribute signatureAttr = (StructGenericSignatureAttribute)attributes.get(StructGeneralAttribute.ATTRIBUTE_SIGNATURE.name); -+ if (signatureAttr != null) { -+ signature = GenericMain.parseFieldSignature(signatureAttr.getSignature()); -+ } -+ } - -- return new StructField(accessFlags, attributes, values[0], values[1]); -+ return new StructField(accessFlags, attributes, values[0], values[1], signature); - } - - private final String name; - private final String descriptor; -+ private final GenericFieldDescriptor signature; - - protected StructField(int accessFlags, Map attributes, String name, String descriptor) { -+ this(accessFlags, attributes, name, descriptor, null); -+ } -+ -+ protected StructField(int accessFlags, Map attributes, String name, String descriptor, GenericFieldDescriptor signature) { - super(accessFlags, attributes); - this.name = name; - this.descriptor = descriptor; -+ this.signature = signature; - } - - public final String getName() { -@@ -58,4 +76,8 @@ public class StructField extends StructMember { - protected Type getType() { - return new VarType(descriptor); - } -+ -+ public GenericFieldDescriptor getSignature() { -+ return signature; -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/src/org/jetbrains/java/decompiler/struct/StructMethod.java -index 0a7e5ba44d82f1923dadd9f79627d91f82b1014c..d48e950e7511d2a00ac9885d5dc7d4ff524bbb37 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructMethod.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructMethod.java -@@ -2,12 +2,17 @@ - package org.jetbrains.java.decompiler.struct; - - import org.jetbrains.java.decompiler.code.*; -+import org.jetbrains.java.decompiler.main.DecompilerContext; -+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.struct.attr.StructCodeAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; -+import org.jetbrains.java.decompiler.struct.attr.StructGenericSignatureAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute; - import org.jetbrains.java.decompiler.struct.consts.ConstantPool; - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.Type; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor; - import org.jetbrains.java.decompiler.util.DataInputFullStream; - import org.jetbrains.java.decompiler.util.VBStyleCollection; - -@@ -41,7 +46,15 @@ public class StructMethod extends StructMember { - attributes.putAll(code.codeAttributes); - } - -- return new StructMethod(accessFlags, attributes, values[0], values[1], bytecodeVersion, own ? code : null, clQualifiedName); -+ GenericMethodDescriptor signature = null; -+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -+ StructGenericSignatureAttribute signatureAttr = (StructGenericSignatureAttribute)attributes.get(StructGeneralAttribute.ATTRIBUTE_SIGNATURE.name); -+ if (signatureAttr != null) { -+ signature = GenericMain.parseMethodSignature(signatureAttr.getSignature()); -+ } -+ } -+ -+ return new StructMethod(accessFlags, attributes, values[0], values[1], bytecodeVersion, own ? code : null, clQualifiedName, signature); - } - - private static final int[] opr_iconst = {-1, 0, 1, 2, 3, 4, 5}; -@@ -58,6 +71,7 @@ public class StructMethod extends StructMember { - private InstructionSequence seq = null; - private boolean expanded = false; - private final String classQualifiedName; -+ private final GenericMethodDescriptor signature; - - private StructMethod(int accessFlags, - Map attributes, -@@ -65,7 +79,8 @@ public class StructMethod extends StructMember { - String descriptor, - int bytecodeVersion, - StructCodeAttribute code, -- String classQualifiedName) { -+ String classQualifiedName, -+ GenericMethodDescriptor signature) { - super(accessFlags, attributes); - this.name = name; - this.descriptor = descriptor; -@@ -79,6 +94,7 @@ public class StructMethod extends StructMember { - this.localVariables = this.codeLength = this.codeFullLength = -1; - } - this.classQualifiedName = classQualifiedName; -+ this.signature = signature; - } - - public void expandData(StructClass classStruct) throws IOException { -@@ -339,4 +355,8 @@ public class StructMethod extends StructMember { - public String getClassQualifiedName() { - return classQualifiedName; - } -+ -+ public GenericMethodDescriptor getSignature() { -+ return signature; -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java b/src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java -index e50983daf2a1bf6c93ec92c99221587d7c4f7c6a..11fa1a3e621221a09c0e611a7f912932f5890fc6 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java -@@ -1,9 +1,14 @@ - // Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - package org.jetbrains.java.decompiler.struct; - -+import org.jetbrains.java.decompiler.main.DecompilerContext; -+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; -+import org.jetbrains.java.decompiler.struct.attr.StructGenericSignatureAttribute; - import org.jetbrains.java.decompiler.struct.consts.ConstantPool; - import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; - import org.jetbrains.java.decompiler.util.DataInputFullStream; - - import java.io.IOException; -@@ -26,11 +31,18 @@ public class StructRecordComponent extends StructField { - String descriptor = ((PrimitiveConstant)pool.getConstant(descriptorIndex)).getString(); - - Map attributes = readAttributes(in, pool); -+ GenericFieldDescriptor signature = null; -+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { -+ StructGenericSignatureAttribute signatureAttr = (StructGenericSignatureAttribute)attributes.get(StructGeneralAttribute.ATTRIBUTE_SIGNATURE.name); -+ if (signatureAttr != null) { -+ signature = GenericMain.parseFieldSignature(signatureAttr.getSignature()); -+ } -+ } - -- return new StructRecordComponent(0, attributes, name, descriptor); -+ return new StructRecordComponent(0, attributes, name, descriptor, signature); - } - -- private StructRecordComponent(int flags, Map attributes, String name, String descriptor) { -- super(flags, attributes, name, descriptor); -+ private StructRecordComponent(int flags, Map attributes, String name, String descriptor, GenericFieldDescriptor signature) { -+ super(flags, attributes, name, descriptor, signature); - } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java -index 267eb5067594bebb435f960b912754a5a2cff9e1..2096754661e845cfe3148d47c5c3ff914bcb0322 100644 ---- a/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java -+++ b/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java -@@ -2,14 +2,24 @@ - package org.jetbrains.java.decompiler.struct.gen; - - import org.jetbrains.java.decompiler.code.CodeConstants; -+import org.jetbrains.java.decompiler.main.DecompilerContext; -+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; -+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; -+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; -+import org.jetbrains.java.decompiler.main.rels.MethodWrapper; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -+import org.jetbrains.java.decompiler.struct.StructMethod; -+import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor; - - import java.util.ArrayList; - import java.util.Arrays; - import java.util.List; -+import java.util.Objects; - - public final class MethodDescriptor { - public final VarType[] params; - public final VarType ret; -+ public GenericMethodDescriptor genericInfo; - - private MethodDescriptor(VarType[] params, VarType ret) { - this.params = params; -@@ -64,6 +74,35 @@ public final class MethodDescriptor { - return new MethodDescriptor(params, ret); - } - -+ public static MethodDescriptor parseDescriptor(StructMethod struct, ClassNode node) { -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(struct.getDescriptor()); -+ -+ GenericMethodDescriptor sig = struct.getSignature(); -+ if (sig != null) { -+ if (node != null) { -+ MethodWrapper methodWrapper = node.getWrapper().getMethodWrapper(struct.getName(), struct.getDescriptor()); -+ boolean init = CodeConstants.INIT_NAME.equals(struct.getName()) && node.type != ClassNode.CLASS_ANONYMOUS; -+ long actualParams = md.params.length; -+ List sigFields = methodWrapper == null ? null : methodWrapper.synthParameters; -+ if (sigFields != null) { -+ actualParams = sigFields.stream().filter(Objects::isNull).count(); -+ } -+ if (actualParams != sig.parameterTypes.size()) { -+ String message = "Inconsistent generic signature in method " + struct.getName() + " " + struct.getDescriptor() + " in " + struct.getClassQualifiedName(); -+ DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); -+ sig = null; -+ } -+ } -+ md.addGenericDescriptor(sig); -+ } -+ -+ return md; -+ } -+ -+ public void addGenericDescriptor(GenericMethodDescriptor desc) { -+ this.genericInfo = desc; -+ } -+ - public String buildNewDescriptor(NewClassNameBuilder builder) { - boolean updated = false; - -@@ -125,4 +164,4 @@ public final class MethodDescriptor { - result = 31 * result + params.length; - return result; - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java -index 2d18843b486376752fa29c03cec82308e9440bf5..f4115448cfa13ba37fb1ee1795903ffb0c79a6af 100644 ---- a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java -+++ b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java -@@ -3,6 +3,7 @@ package org.jetbrains.java.decompiler.struct.gen; - - import org.jetbrains.java.decompiler.code.CodeConstants; - -+import java.util.Map; - import java.util.Objects; - - public class VarType implements Type { // TODO: optimize switch -@@ -50,7 +51,7 @@ public class VarType implements Type { // TODO: optimize switch - this(type, arrayDim, value, getFamily(type, arrayDim), getStackSize(type, arrayDim), false); - } - -- private VarType(int type, int arrayDim, String value, int typeFamily, int stackSize, boolean falseBoolean) { -+ protected VarType(int type, int arrayDim, String value, int typeFamily, int stackSize, boolean falseBoolean) { - this.type = type; - this.arrayDim = arrayDim; - this.value = value; -@@ -147,7 +148,7 @@ public class VarType implements Type { // TODO: optimize switch - }; - } - -- private static int getStackSize(int type, int arrayDim) { -+ protected static int getStackSize(int type, int arrayDim) { - if (arrayDim > 0) { - return 1; - } -@@ -159,7 +160,7 @@ public class VarType implements Type { // TODO: optimize switch - }; - } - -- private static int getFamily(int type, int arrayDim) { -+ protected static int getFamily(int type, int arrayDim) { - if (arrayDim > 0) { - return CodeConstants.TYPE_FAMILY_OBJECT; - } -@@ -248,6 +249,15 @@ public class VarType implements Type { // TODO: optimize switch - return res; - } - -+ @Override -+ public int hashCode() { -+ int result = 1; -+ result = 37 * result + type; -+ result = 37 * result + arrayDim; -+ result = 37 * result + (value == null ? 0 : value.hashCode()); -+ return result; -+ } -+ - @Override - public boolean equals(Object o) { - if (o == this) { -@@ -373,4 +383,15 @@ public class VarType implements Type { // TODO: optimize switch - default -> throw new IllegalArgumentException("Invalid type: " + c); - }; - } -+ -+ public boolean isGeneric() { -+ return false; -+ } -+ -+ public VarType remap(Map map) { -+ if (map.containsKey(this)) { -+ return map.get(this); -+ } -+ return this; -+ } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java -index ad623a2ab64debaf17974ae0a0757986f4cfbadf..ae2a3dd9085efea75979bbac66b1af29c52aa138 100644 ---- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java -+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java -@@ -4,13 +4,17 @@ package org.jetbrains.java.decompiler.struct.gen.generics; - import java.util.ArrayList; - import java.util.List; - -+import org.jetbrains.java.decompiler.struct.gen.VarType; -+ - public class GenericClassDescriptor { - -- public GenericType superclass; -+ public VarType superclass; -+ -+ public GenericType genericType; - -- public final List superinterfaces = new ArrayList<>(); -+ public final List superinterfaces = new ArrayList<>(); - - public final List fparameters = new ArrayList<>(); - -- public final List> fbounds = new ArrayList<>(); -+ public final List> fbounds = new ArrayList<>(); - } -diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java -index a65181762765bfdc9d2ee5695f3ffa68b7768b74..2b0fdf1dad01ec62f3e21f372297c124d859e8ff 100644 ---- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java -+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java -@@ -1,10 +1,12 @@ - // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - package org.jetbrains.java.decompiler.struct.gen.generics; - -+import org.jetbrains.java.decompiler.struct.gen.VarType; -+ - public class GenericFieldDescriptor { -- public final GenericType type; -+ public final VarType type; - -- public GenericFieldDescriptor(GenericType type) { -+ public GenericFieldDescriptor(VarType type) { - this.type = type; - } - } -\ No newline at end of file -diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java -index 315786d5a56e2871a1d0829760b672398a17d972..16aa2ee5a55fa9ba832909cdd9f5043f5d3e7ba7 100644 ---- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java -+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java -@@ -7,9 +7,9 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; - import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.typeann.TypeAnnotationWriteHelper; - import org.jetbrains.java.decompiler.struct.StructTypePathEntry; -+import org.jetbrains.java.decompiler.struct.gen.VarType; - - import java.util.ArrayList; --import java.util.Arrays; - import java.util.List; - import java.util.stream.Collectors; - -@@ -26,7 +26,7 @@ public final class GenericMain { - "boolean", - }; - -- public static GenericClassDescriptor parseClassSignature(String signature) { -+ public static GenericClassDescriptor parseClassSignature(String qualifiedName, String signature) { - String original = signature; - try { - GenericClassDescriptor descriptor = new GenericClassDescriptor(); -@@ -34,15 +34,23 @@ public final class GenericMain { - signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); - - String superCl = GenericType.getNextType(signature); -- descriptor.superclass = new GenericType(superCl); -+ descriptor.superclass = GenericType.parse(superCl); - - signature = signature.substring(superCl.length()); - while (signature.length() > 0) { - String superIf = GenericType.getNextType(signature); -- descriptor.superinterfaces.add(new GenericType(superIf)); -+ descriptor.superinterfaces.add(GenericType.parse(superIf)); - signature = signature.substring(superIf.length()); - } - -+ StringBuilder buf = new StringBuilder(); -+ buf.append('L').append(qualifiedName).append('<'); -+ for (String t : descriptor.fparameters) { -+ buf.append('T').append(t).append(';'); -+ } -+ buf.append(">;"); -+ descriptor.genericType = (GenericType)GenericType.parse(buf.toString()); -+ - return descriptor; - } - catch (RuntimeException e) { -@@ -53,7 +61,7 @@ public final class GenericMain { - - public static GenericFieldDescriptor parseFieldSignature(String signature) { - try { -- return new GenericFieldDescriptor(new GenericType(signature)); -+ return new GenericFieldDescriptor(GenericType.parse(signature)); - } - catch (RuntimeException e) { - DecompilerContext.getLogger().writeMessage("Invalid signature: " + signature, IFernflowerLogger.Severity.WARN); -@@ -65,29 +73,29 @@ public final class GenericMain { - String original = signature; - try { - List typeParameters = new ArrayList<>(); -- List> typeParameterBounds = new ArrayList<>(); -+ List> typeParameterBounds = new ArrayList<>(); - signature = parseFormalParameters(signature, typeParameters, typeParameterBounds); - - int to = signature.indexOf(")"); - String parameters = signature.substring(1, to); - signature = signature.substring(to + 1); - -- List parameterTypes = new ArrayList<>(); -+ List parameterTypes = new ArrayList<>(); - while (parameters.length() > 0) { - String par = GenericType.getNextType(parameters); -- parameterTypes.add(new GenericType(par)); -+ parameterTypes.add(GenericType.parse(par)); - parameters = parameters.substring(par.length()); - } - - String ret = GenericType.getNextType(signature); -- GenericType returnType = new GenericType(ret); -+ VarType returnType = GenericType.parse(ret); - signature = signature.substring(ret.length()); - -- List exceptionTypes = new ArrayList<>(); -+ List exceptionTypes = new ArrayList<>(); - if (signature.length() > 0) { - String[] exceptions = signature.split("\\^"); - for (int i = 1; i < exceptions.length; i++) { -- exceptionTypes.add(new GenericType(exceptions[i])); -+ exceptionTypes.add(GenericType.parse(exceptions[i])); - } - } - -@@ -99,7 +107,7 @@ public final class GenericMain { - } - } - -- private static String parseFormalParameters(String signature, List parameters, List> bounds) { -+ private static String parseFormalParameters(String signature, List parameters, List> bounds) { - if (signature.charAt(0) != '<') { - return signature; - } -@@ -131,7 +139,7 @@ public final class GenericMain { - String param = value.substring(0, to); - value = value.substring(to + 1); - -- List lstBounds = new ArrayList<>(); -+ List lstBounds = new ArrayList<>(); - - while (true) { - if (value.charAt(0) == ':') { -@@ -140,7 +148,7 @@ public final class GenericMain { - } - - String bound = GenericType.getNextType(value); -- lstBounds.add(new GenericType(bound)); -+ lstBounds.add(GenericType.parse(bound)); - value = value.substring(bound.length()); - - -@@ -183,77 +191,14 @@ public final class GenericMain { - } - else if (tp == CodeConstants.TYPE_OBJECT) { - StringBuilder sb = new StringBuilder(); -- appendClassName(type, sb, typeAnnWriteHelpers); -+ type.appendCastName(sb, typeAnnWriteHelpers); - return sb.toString(); - } - - throw new RuntimeException("Invalid type: " + type); - } - -- private static void appendClassName(GenericType type, StringBuilder sb, List typeAnnWriteHelpers) { -- List enclosingTypes = type.getEnclosingClasses(); -- typeAnnWriteHelpers = ExprProcessor.writeTypeAnnotationBeforeType(type, sb, typeAnnWriteHelpers); -- if (enclosingTypes.isEmpty()) { -- List nestedTypes = Arrays.asList( -- DecompilerContext.getImportCollector().getNestedName(type.getValue().replace('/', '.')).split("\\.") -- ); -- ExprProcessor.writeNestedClass(sb, type, nestedTypes, typeAnnWriteHelpers); -- ExprProcessor.popNestedTypeAnnotation(typeAnnWriteHelpers); -- } -- else { -- for (GenericType tp : enclosingTypes) { -- List nestedTypes = Arrays.asList( -- DecompilerContext.getImportCollector().getNestedName(tp.getValue().replace('/', '.')).split("\\.") -- ); -- typeAnnWriteHelpers = ExprProcessor.writeNestedClass(sb, type, nestedTypes, typeAnnWriteHelpers); -- typeAnnWriteHelpers = appendTypeArguments(tp, sb, typeAnnWriteHelpers); -- ExprProcessor.popNestedTypeAnnotation(typeAnnWriteHelpers); -- sb.append('.'); -- } -- typeAnnWriteHelpers = ExprProcessor.writeNestedTypeAnnotations(sb, typeAnnWriteHelpers); -- ExprProcessor.popNestedTypeAnnotation(typeAnnWriteHelpers); -- sb.append(type.getValue()); -- } -- appendTypeArguments(type, sb, typeAnnWriteHelpers); -- } -- -- private static List appendTypeArguments( -- GenericType type, -- StringBuilder sb, -- List typeAnnWriteHelpers -- ) { -- if (!type.getArguments().isEmpty()) { -- sb.append('<'); -- -- for (int i = 0; i < type.getArguments().size(); i++) { -- if (i > 0) { -- sb.append(", "); -- } -- -- GenericType genPar = type.getArguments().get(i); -- int wildcard = type.getWildcards().get(i); -- -- // only take type paths that are in the generic -- List locTypeAnnWriteHelpers = getGenericTypeAnnotations(i, typeAnnWriteHelpers); -- typeAnnWriteHelpers.removeAll(locTypeAnnWriteHelpers); -- locTypeAnnWriteHelpers = writeTypeAnnotationBeforeWildCard(sb, genPar, wildcard, locTypeAnnWriteHelpers); -- switch (wildcard) { -- case GenericType.WILDCARD_UNBOUND -> sb.append('?'); -- case GenericType.WILDCARD_EXTENDS -> sb.append("? extends "); -- case GenericType.WILDCARD_SUPER -> sb.append("? super "); -- } -- locTypeAnnWriteHelpers = writeTypeAnnotationAfterWildCard(sb, genPar, locTypeAnnWriteHelpers); -- if (genPar != null) { -- sb.append(getGenericCastTypeName(genPar, locTypeAnnWriteHelpers)); -- } -- } -- -- sb.append(">"); -- } -- return typeAnnWriteHelpers; -- } -- -- private static List getGenericTypeAnnotations( -+ public static List getGenericTypeAnnotations( - int argIndex, - List typeAnnWriteHelpers - ) { -@@ -266,9 +211,9 @@ public final class GenericMain { - }).collect(Collectors.toList()); - } - -- private static List writeTypeAnnotationBeforeWildCard( -+ public static List writeTypeAnnotationBeforeWildCard( - StringBuilder sb, -- GenericType type, -+ VarType type, - int wildcard, - List typeAnnWriteHelpers - ) { -@@ -278,7 +223,7 @@ public final class GenericMain { - typeAnnWriteHelper.writeTo(sb); - return false; - } -- if (type.getArrayDim() == typeAnnWriteHelper.getPaths().size() && type.getArrayDim() == typeAnnWriteHelper.arrayPathCount()) { -+ if (type != null && type.getArrayDim() == typeAnnWriteHelper.getPaths().size() && type.getArrayDim() == typeAnnWriteHelper.arrayPathCount()) { - typeAnnWriteHelper.writeTo(sb); - return false; - } -@@ -286,9 +231,9 @@ public final class GenericMain { - }).collect(Collectors.toList()); - } - -- private static List writeTypeAnnotationAfterWildCard( -+ public static List writeTypeAnnotationAfterWildCard( - StringBuilder sb, -- GenericType type, -+ VarType type, - List typeAnnWriteHelpers - ) { - typeAnnWriteHelpers.forEach(typeAnnWriteHelper -> { // remove all wild card path entries -diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java -index eb8049193e952f7476a99188838b6c8907f49f8d..a93d250e2400a9680d7561d73cc1a69f7c0f8d79 100644 ---- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java -+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java -@@ -4,18 +4,20 @@ package org.jetbrains.java.decompiler.struct.gen.generics; - import java.util.Collections; - import java.util.List; - -+import org.jetbrains.java.decompiler.struct.gen.VarType; -+ - public class GenericMethodDescriptor { - public final List typeParameters; -- public final List> typeParameterBounds; -- public final List parameterTypes; -- public final GenericType returnType; -- public final List exceptionTypes; -+ public final List> typeParameterBounds; -+ public final List parameterTypes; -+ public final VarType returnType; -+ public final List exceptionTypes; - - public GenericMethodDescriptor(List typeParameters, -- List> typeParameterBounds, -- List parameterTypes, -- GenericType returnType, -- List exceptionTypes) { -+ List> typeParameterBounds, -+ List parameterTypes, -+ VarType returnType, -+ List exceptionTypes) { - this.typeParameters = substitute(typeParameters); - this.typeParameterBounds = substitute(typeParameterBounds); - this.parameterTypes = substitute(parameterTypes); -diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java -index a042dd3a747f224a63a0987ff465f6259d783de4..e430a99b30757bb0ba5b8dda66e0790383ab8d75 100644 ---- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java -+++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java -@@ -2,44 +2,49 @@ - package org.jetbrains.java.decompiler.struct.gen.generics; - - import org.jetbrains.java.decompiler.code.CodeConstants; -+import org.jetbrains.java.decompiler.main.DecompilerContext; -+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; -+import org.jetbrains.java.decompiler.modules.decompiler.typeann.TypeAnnotationWriteHelper; - import org.jetbrains.java.decompiler.struct.gen.Type; - import org.jetbrains.java.decompiler.struct.gen.VarType; - - import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Collections; - import java.util.List; -+import java.util.Map; -+import java.util.regex.Pattern; - --public class GenericType implements Type { -+public class GenericType extends VarType implements Type { - - public static final int WILDCARD_EXTENDS = 1; - public static final int WILDCARD_SUPER = 2; - public static final int WILDCARD_UNBOUND = 3; - public static final int WILDCARD_NO = 4; - -- private final int type; -- private final int arrayDim; -- private final String value; -+ private static final Pattern DOT_SPLIT = Pattern.compile("\\."); - -- private final List enclosingClasses = new ArrayList<>(); -- private final List arguments = new ArrayList<>(); -- private final List wildcards = new ArrayList<>(); -+ private final VarType parent; -+ private final List arguments; -+ private final int wildcard; - -- public GenericType(int type, int arrayDim, String value) { -- this.type = type; -- this.arrayDim = arrayDim; -- this.value = value; -+ public GenericType(int type, int arrayDim, String value, VarType parent, List arguments, int wildcard) { -+ super(type, arrayDim, value, getFamily(type, arrayDim), getStackSize(type, arrayDim), false); -+ this.parent = parent; -+ this.arguments = arguments == null ? Collections.emptyList() : arguments; -+ this.wildcard = wildcard; - } - -- private GenericType(GenericType other, int arrayDim) { -- this(other.getType(), arrayDim, other.getValue()); -- enclosingClasses.addAll(other.enclosingClasses); -- arguments.addAll(other.arguments); -- wildcards.addAll(other.wildcards); -+ public static VarType parse(String signature) { -+ return parse(signature, WILDCARD_NO); - } - -- public GenericType(String signature) { -+ public static VarType parse(String signature, int wildcard) { - int type = 0; - int arrayDim = 0; - String value = null; -+ List params = null; -+ VarType parent = null; - - int index = 0; - loop: -@@ -57,32 +62,54 @@ public class GenericType implements Type { - case 'L': - type = CodeConstants.TYPE_OBJECT; - signature = signature.substring(index + 1, signature.length() - 1); -+ String cl = getNextClassSignature(signature); - -- while (true) { -- String cl = getNextClassSignature(signature); -- -- String name = cl; -- String args = null; -- -- int argStart = cl.indexOf("<"); -+ if (cl.length() == signature.length()) { -+ int argStart = cl.indexOf('<'); - if (argStart >= 0) { -- name = cl.substring(0, argStart); -- args = cl.substring(argStart + 1, cl.length() - 1); -- } -- -- if (cl.length() < signature.length()) { -- signature = signature.substring(cl.length() + 1); // skip '.' -- GenericType type11 = new GenericType(CodeConstants.TYPE_OBJECT, 0, name); -- parseArgumentsList(args, type11); -- enclosingClasses.add(type11); -+ value = cl.substring(0, argStart); -+ params = parseArgumentsList(cl.substring(argStart + 1, cl.length() - 1)); - } - else { -- value = name; -- parseArgumentsList(args, this); -- break; -+ value = cl; -+ } -+ } -+ else { -+ StringBuilder name_buff = new StringBuilder(); -+ while (signature.length() > 0) { -+ String name = cl; -+ String args = null; -+ -+ int argStart = cl.indexOf('<'); -+ if (argStart >= 0) { -+ name = cl.substring(0, argStart); -+ args = cl.substring(argStart + 1, cl.length() - 1); -+ } -+ -+ if (name_buff.length() > 0) { -+ name_buff.append('$'); -+ } -+ name_buff.append(name); -+ -+ value = name_buff.toString(); -+ params = args == null ? null : parseArgumentsList(args); -+ -+ if (cl.length() == signature.length()) { -+ break; -+ } -+ else { -+ if (parent == null && params == null) { -+ parent = GenericType.parse("L" + value + ";"); -+ } -+ else { -+ parent = new GenericType(CodeConstants.TYPE_OBJECT, 0, value, parent, params, wildcard); -+ } -+ -+ signature = signature.substring(cl.length() + 1); -+ } -+ cl = getNextClassSignature(signature); - } - } -- - break loop; - - default: -@@ -93,24 +120,20 @@ public class GenericType implements Type { - index++; - } - -- this.type = type; -- this.arrayDim = arrayDim; -- this.value = value; -- } -- -- @Override -- public int getType() { -- return type; -- } -- -- @Override -- public int getArrayDim() { -- return arrayDim; -- } -- -- @Override -- public String getValue() { -- return value; -+ if (type == CodeConstants.TYPE_GENVAR) { -+ return new GenericType(type, arrayDim, value, null, null, wildcard); -+ } -+ else if (type == CodeConstants.TYPE_OBJECT) { -+ if (parent == null && params == null && wildcard == WILDCARD_NO) { -+ return new VarType(type, arrayDim, value); -+ } -+ else { -+ return new GenericType(type, arrayDim, value, parent, params, wildcard); -+ } -+ } -+ else { -+ return new VarType(type, arrayDim, value); -+ } - } - - private static String getNextClassSignature(String value) { -@@ -135,11 +158,13 @@ public class GenericType implements Type { - return value.substring(0, index); - } - -- private static void parseArgumentsList(String value, GenericType type) { -+ private static List parseArgumentsList(String value) { - if (value == null) { -- return; -+ return null; - } - -+ List args = new ArrayList<>(); -+ - while (value.length() > 0) { - String typeStr = getNextType(value); - int len = typeStr.length(); -@@ -150,16 +175,16 @@ public class GenericType implements Type { - default -> WILDCARD_NO; - }; - -- type.getWildcards().add(wildcard); -- - if (wildcard != WILDCARD_NO) { - typeStr = typeStr.substring(1); - } - -- type.getArguments().add(typeStr.length() == 0 ? null : new GenericType(typeStr)); -+ args.add(typeStr.length() == 0 ? null : GenericType.parse(typeStr, wildcard)); - - value = value.substring(len); - } -+ -+ return args; - } - - public static String getNextType(String value) { -@@ -208,20 +233,134 @@ public class GenericType implements Type { - return value.substring(0, index + 1); - } - -+ @Override - public GenericType decreaseArrayDim() { - assert getArrayDim() > 0 : this; -- return new GenericType(this, getArrayDim() - 1); -+ return new GenericType(getType(), getArrayDim() - 1, getValue(), parent, arguments, wildcard); -+ } -+ -+ @Override -+ public VarType resizeArrayDim(int newArrayDim) { -+ return new GenericType(getType(), newArrayDim, getValue(), parent, arguments, wildcard); -+ } -+ -+ public VarType getParent() { -+ return parent; - } - -- public List getArguments() { -+ public List getArguments() { - return arguments; - } - -- public List getEnclosingClasses() { -- return enclosingClasses; -+ @Override -+ public boolean isGeneric() { -+ return true; -+ } -+ -+ public int getWildcard() { -+ return wildcard; -+ } -+ -+ public List appendCastName(final StringBuilder clsName, List typeAnnWriteHelpers) { -+ if (parent != null && parent.isGeneric()) { -+ typeAnnWriteHelpers = ((GenericType) parent).appendCastName(clsName, typeAnnWriteHelpers); -+ typeAnnWriteHelpers = ExprProcessor.writeNestedTypeAnnotations(clsName, typeAnnWriteHelpers); -+ clsName.append(".").append(getValue().substring(parent.getValue().length() + 1)); -+ } -+ else { -+ List nestedTypes = Arrays.asList(DOT_SPLIT.split(DecompilerContext.getImportCollector().getNestedName(getValue().replace('/', '.')))); -+ ExprProcessor.writeNestedClass(clsName, this, nestedTypes, typeAnnWriteHelpers); -+ ExprProcessor.popNestedTypeAnnotation(typeAnnWriteHelpers); -+ } -+ typeAnnWriteHelpers = appendTypeArguments(clsName, typeAnnWriteHelpers); -+ return typeAnnWriteHelpers; -+ } -+ -+ private List appendTypeArguments(final StringBuilder buffer, List typeAnnWriteHelpers) { -+ if (!arguments.isEmpty()) { -+ buffer.append('<'); -+ -+ for (int i = 0; i < arguments.size(); i++) { -+ if (i > 0) { -+ buffer.append(", "); -+ } -+ -+ VarType par = arguments.get(i); -+ // only take type paths that are in the generic -+ List locTypeAnnWriteHelpers = GenericMain.getGenericTypeAnnotations(i, typeAnnWriteHelpers); -+ typeAnnWriteHelpers.removeAll(locTypeAnnWriteHelpers); -+ locTypeAnnWriteHelpers = GenericMain.writeTypeAnnotationBeforeWildCard(buffer, par, wildcard, locTypeAnnWriteHelpers); -+ if (par == null) { // Wildcard unbound -+ buffer.append('?'); -+ } -+ else if (par.isGeneric()) { -+ GenericType gen = (GenericType)par; -+ switch (gen.getWildcard()) { -+ case GenericType.WILDCARD_EXTENDS: -+ buffer.append("? extends "); -+ break; -+ case GenericType.WILDCARD_SUPER: -+ buffer.append("? super "); -+ break; -+ } -+ locTypeAnnWriteHelpers = GenericMain.writeTypeAnnotationAfterWildCard(buffer, par, locTypeAnnWriteHelpers); -+ buffer.append(GenericMain.getGenericCastTypeName(gen, locTypeAnnWriteHelpers)); -+ } -+ else { -+ buffer.append(ExprProcessor.getCastTypeName(par, locTypeAnnWriteHelpers)); -+ } -+ } -+ -+ buffer.append(">"); -+ } -+ return typeAnnWriteHelpers; -+ } -+ -+ @Override -+ public String toString() { -+ StringBuilder buf = new StringBuilder(); -+ switch(getWildcard()) { -+ case GenericType.WILDCARD_EXTENDS: -+ buf.append("? extends "); -+ break; -+ case GenericType.WILDCARD_SUPER: -+ buf.append("? super "); -+ break; -+ } -+ buf.append(super.toString()); -+ appendTypeArguments(buf, Collections.emptyList()); -+ return buf.toString(); - } - -- public List getWildcards() { -- return wildcards; -+ -+ @Override -+ public VarType remap(Map map) { -+ VarType main = super.remap(map); -+ if (main != this) { -+ return main; -+ } -+ boolean changed = false; -+ VarType parent = getParent(); -+ if (map.containsKey(parent)) { -+ parent = map.get(parent); -+ changed = true; -+ } -+ List newArgs = new ArrayList<>(); -+ for (VarType arg : getArguments()) { -+ VarType newArg = null; -+ if (arg != null) { -+ newArg = arg.remap(map); -+ } -+ if (newArg != arg) { -+ newArgs.add(newArg); -+ changed = true; -+ } else { -+ newArgs.add(arg); -+ } -+ } -+ if (changed) { -+ return new GenericType(main.getType(), main.getArrayDim(), main.getValue(), parent, newArgs, getWildcard()); -+ } -+ return this; - } - } -diff --git a/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java b/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java -index 8b6105dbbfea358241702acbc691976d51f0d726..4261dce0b37505d22c6e9ee7c3e0bdb7e5331cfb 100644 ---- a/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java -+++ b/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java -@@ -119,7 +119,7 @@ public class LazyLoader { - - public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException { - Link link = mapClassLinks.get(qualifiedClassName); -- return link == null ? null : getClassStream(link.externalPath, link.internalPath); -+ return link == null ? null : link.data != null ? new DataInputFullStream(link.data) : getClassStream(link.externalPath, link.internalPath); - } - - public static void skipAttributes(DataInputFullStream in) throws IOException { -@@ -133,10 +133,16 @@ public class LazyLoader { - public static class Link { - public final String externalPath; - public final String internalPath; -+ public final byte[] data; - - public Link(String externalPath, String internalPath) { -+ this(externalPath, internalPath, null); -+ } -+ -+ public Link(String externalPath, String internalPath, byte[] data) { - this.externalPath = externalPath; - this.internalPath = internalPath; -+ this.data = data; - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/util/ClasspathScanner.java b/src/org/jetbrains/java/decompiler/util/ClasspathScanner.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cc91edd842805b55a757c5794b4fb7dcc1da3f57 ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/util/ClasspathScanner.java -@@ -0,0 +1,77 @@ -+// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -+package org.jetbrains.java.decompiler.util; -+ -+import java.lang.module.*; -+import java.nio.ByteBuffer; -+import java.io.File; -+import java.io.IOException; -+import java.util.HashSet; -+import java.util.Optional; -+import java.util.Set; -+ -+import org.jetbrains.java.decompiler.main.DecompilerContext; -+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger.Severity; -+import org.jetbrains.java.decompiler.struct.StructContext; -+ -+public class ClasspathScanner { -+ -+ public static void addAllClasspath(StructContext ctx) { -+ Set found = new HashSet<>(); -+ String[] props = { System.getProperty("java.class.path"), System.getProperty("sun.boot.class.path") }; -+ for (String prop : props) { -+ if (prop == null) -+ continue; -+ -+ for (final String path : prop.split(File.pathSeparator)) { -+ File file = new File(path); -+ if (found.contains(file.getAbsolutePath())) -+ continue; -+ -+ if (file.exists() && (file.getName().endsWith(".class") || file.getName().endsWith(".jar"))) { -+ DecompilerContext.getLogger().writeMessage("Adding File to context from classpath: " + file, Severity.INFO); -+ ctx.addSpace(file, false); -+ found.add(file.getAbsolutePath()); -+ } -+ } -+ } -+ -+ addAllModulePath(ctx); -+ } -+ -+ private static void addAllModulePath(StructContext ctx) { -+ for (ModuleReference module : ModuleFinder.ofSystem().findAll()) { -+ String name = module.descriptor().name(); -+ try { -+ ModuleReader reader = module.open(); -+ DecompilerContext.getLogger().writeMessage("Reading Module: " + name, Severity.INFO); -+ reader.list().forEach(cls -> { -+ if (!cls.endsWith(".class") || cls.contains("module-info.class")) -+ return; -+ -+ DecompilerContext.getLogger().writeMessage(" " + cls, Severity.INFO); -+ try { -+ Optional bb = reader.read(cls); -+ if (!bb.isPresent()) { -+ DecompilerContext.getLogger().writeMessage(" Error Reading Class: " + cls, Severity.ERROR); -+ return; -+ } -+ -+ byte[] data; -+ if (bb.get().hasArray()) { -+ data = bb.get().array(); -+ } else { -+ data = new byte[bb.get().remaining()]; -+ bb.get().get(data); -+ } -+ ctx.addData(name, cls, data, false); -+ } catch (IOException e) { -+ DecompilerContext.getLogger().writeMessage(" Error Reading Class: " + cls, e); -+ } -+ }); -+ reader.close(); -+ } catch (IOException e) { -+ DecompilerContext.getLogger().writeMessage("Error loading module " + name, e); -+ } -+ } -+ } -+} -diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java -index dd0e178cc1df1c6edc9e77e3149c2b0e9bffe884..645d99f07322c311a20b5fd76a5235de6cdae74d 100644 ---- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java -+++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java -@@ -23,9 +23,12 @@ public class SingleClassesTest extends SingleClassesTestBase { - return Map.of(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", - IFernflowerPreferences.DUMP_ORIGINAL_LINES, "1", - IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", -- IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1"); -+ IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", -+ IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "1" -+); - } - -+ @Test public void testGenerics() { doTest("pkg/TestGenerics"); } - @Test public void testEnhancedForLoops() { doTest("pkg/TestEnhancedForLoops"); } - @Test public void testPrimitiveNarrowing() { doTest("pkg/TestPrimitiveNarrowing"); } - @Test public void testClassFields() { doTest("pkg/TestClassFields"); } -diff --git a/testData/classes/pkg/TestGenerics$Maps.class b/testData/classes/pkg/TestGenerics$Maps.class -new file mode 100644 -index 0000000000000000000000000000000000000000..a4c3dcc2e336bb973e3eac43506e0b949eca8ea9 -GIT binary patch -literal 544 -zcmZutO;5r=5Pb`U(u(q-h#wbCJb(v#@ni`HF`}XBfriB6Qa7+z3+adcEj^KF;t%jg -z8E1}m_fG()*f)_wO~eh05wmY!f>goP82|aNs)t@TM!=0!hipWE!#J_=b?9r$zKg3W@kY6OA&WKwO9eE`u1CEX~kDOVcx%=~2nP?}=HS -z@{niWa!&9BLp;gxIsYU15jjcBt?Hhh9*8-|2fDkezPjK2?suzu`0byce+BR)zD^*5 -zNeve?^wePso=cz(7d2c;pca!!Y`|p=SL*OQUeNGj0!d89@shk7@-iha*#xFx%H3Br -z%p@@jD~W5EOTxyyyf_+iayhTzWeGVa2L%m9IdCqcM6wd_6y4hYm`tQp5}O9fM4fAwn08`_35)0c4zmNPRDni4PU@Qo% -zy&PhBdg_{)l_X-9Cx&>dO<9iR4hlp&Iwv_hlAC7XYtoiuj+f@A%)*2*Wpk!Eoy!{b -zq*1Ws*q@BKvli(zr}J|&eG_KUJz-L0D_bORYxRbOe0kG`RnaLjnHW~2n`S(OA=_p? -z*UC9m(4QN1u9^kY$&yWsGPtZPq{B(0IO}!r(CXQ+K&v}9>bT~NSx^L$elpny_EF~X -z9>tVE+bZfirMp;dODLymp5sos3Sa%VkmWzYd(L2CFRHXc!gUW32RMz(0cP=#)4)a|)eCQ#9hn16Z4-AIb1r|?aa-~AnJZ?z? -zH--JVTh^juH~MI=N?qPg9o^{BaRWE$Ftw;oraDbBnT`d#!j`Wzz4C&FS9QFG*J+jt -zu4lR7l4Vbu1%b%$AsuhvO?i1s$J=;E!@D}(!}~h6V+Xlbvii2x@PUpG@sWm)b$o(P -z*+m_n;d32d;8s-)UM?Mv;|YO=3XsRVQ_hAe_WGgYOMJ!ol@+n;6@XFKEEsN%{1c9O -z!{`PzJ6wfq-D -zzFX@nTJkWmq&agTBSmT|=TSc66lsToRZQFp#}Jp6guqUYBG|<-ofV8bIHsq9aTlX_dV+B;Kl(zR -zGhX|-c9s}|_olA95M7OlUl6&E=#Pl~z{x1~@G5^d0BuaY5qtThdmFHiKPrHys%G|c -zByb>rAM@esyBgO$6#6kjZV5rxuY#5{61omg2hhiuNHVYa2{oryvfWO$I|9fU0}tX5 -zgUf8anE}N%6+nK+ildzCy@%S1ccG=bqsxd#a36JJi%8rVf)I#o4pNszYn}n`jV6D3PR9iISCiQAbJKiyBfw4hK}P -za7DHyzKG`g{O(p*c -zbpp$15lDA0qgCKrwDF-$P@?rxBFfTq`@tWQO-z}`)1;sN-9tt8(u?~7R@<2II8G>j -zJwCs3gP4yqlGRE6B@y`x4H`!O#3qt^HX!$nPp*Fv?d4u=SjNUjCAgnWIlz?CUIzn$ -zyFvu}R}qvmRRo&@f~N=*QRnM>-lZ%0%a&TiCdF^8#}{xtAC!Qb$Gdx%@mK^GZa?_F -zqF^g(xIaZl9OjuHB*`O0KdMMd&+Oz%8e^(QWs-4fJ+3?^_4K-2rt7Vpri@bA21Ncw -zlZG>j`)2>Ga+a9q0+9z)hk%VdX?M`dtUzNj*o -TQ1|n+f_$g&hdmGdR@D6qBizOe - -literal 0 -HcmV?d00001 - -diff --git a/testData/results/TestAmbiguousCall.dec b/testData/results/TestAmbiguousCall.dec -index dec7ba0f20eecdc5a3c7d0774a0fdd4f3b68e6f6..acf1120655937c0e227ab11a1f472c444b2857b9 100644 ---- a/testData/results/TestAmbiguousCall.dec -+++ b/testData/results/TestAmbiguousCall.dec -@@ -13,7 +13,7 @@ class TestAmbiguousCall { - this.m1(var1, "IAE");// 10 - IllegalArgumentException var2 = new IllegalArgumentException();// 12 - this.m1((RuntimeException)var2, "RE");// 13 -- this.m1((IllegalArgumentException)var2, "IAE");// 14 -+ this.m1(var2, "IAE");// 14 - }// 15 - } - -diff --git a/testData/results/TestClassSwitch.dec b/testData/results/TestClassSwitch.dec -index 6a2b156f9ad0e29aad668542ee090d63130d2182..f92c9169b960ab9f1f5ff7440ac4caef9aa62744 100644 ---- a/testData/results/TestClassSwitch.dec -+++ b/testData/results/TestClassSwitch.dec -@@ -2,13 +2,13 @@ package pkg; - - public class TestClassSwitch { - public void testCaseOrder(int var1) { -- switch (var1) {// 22 -+ switch(var1) {// 22 - case 5: -- System.out.println(5);// 27 -+ System.out.println((int)5);// 27 - default: - return;// 29 - case 13: -- System.out.println(13);// 24 -+ System.out.println((int)13);// 24 - } - }// 25 - } -diff --git a/testData/results/TestExtendsList.dec b/testData/results/TestExtendsList.dec -index 6f116dbad41c3ce71fd5c79ee639ddbff3f1b39f..3f3dbea1836b9acaa8626c029bfe40dc0ee3c751 100644 ---- a/testData/results/TestExtendsList.dec -+++ b/testData/results/TestExtendsList.dec -@@ -2,11 +2,11 @@ package pkg; - - public class TestExtendsList { - static > T m1(T var0) { -- return null;// 20 -+ return (T)null;// 20 - } - - static > T m2(T var0) { -- return null;// 24 -+ return (T)null;// 24 - } - } - -diff --git a/testData/results/TestGenerics.dec b/testData/results/TestGenerics.dec -new file mode 100644 -index 0000000000000000000000000000000000000000..da090b301d5537352bad9fb01068cc37fa156cc0 ---- /dev/null -+++ b/testData/results/TestGenerics.dec -@@ -0,0 +1,218 @@ -+package pkg; -+ -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+ -+public class TestGenerics { -+ static Map field = TestGenerics.Maps.newHashMap(); -+ static List> llstring = new ArrayList>(); -+ static List bytes = new ArrayList(); -+ A[] aArray = (A[])(new Object[10]); -+ -+ public void genericAllocation() { -+ this.aArray = (A[])(new Object[20]);// 30 -+ }// 31 -+ -+ public static void genericInference() { -+ HashMap test = TestGenerics.Maps.newHashMap();// 34 -+ }// 35 -+ -+ public void genericList() { -+ List testList = new ArrayList();// 38 -+ B b = testList.get(0);// 39 -+ System.out.println("B:" + b);// 40 -+ }// 41 -+ -+ public void genericCast() { -+ HashMap upcast = (HashMap)field;// 44 -+ }// 45 -+ -+ public void genericForEach() { -+ for(String s : field.keySet()) {// 48 -+ System.out.println(s);// 49 -+ } -+// 51 -+ } -+ -+ public void genericForEachWithCast() {// 54 -+ for(String s : llstring.get(0)) {// 55 -+ System.out.println(s); -+ }// 57 -+ -+ } -+// 60 -+ public void genericSuperUp() { -+ List list = new ArrayList();// 61 -+// 62 -+ for(Number number : bytes) { -+ list.add(number);// 64 -+ } -+ -+ } -+// 68 -+ public static class Maps { -+ public static HashMap newHashMap() { -+ return new HashMap(); -+ } -+ } -+} -+ -+class 'pkg/TestGenerics' { -+ method 'genericAllocation ()V' { -+ 0 14 -+ 1 14 -+ 2 14 -+ 6 14 -+ 7 14 -+ 8 14 -+ 9 14 -+ a 14 -+ b 14 -+ c 15 -+ } -+ -+ method 'genericInference ()V' { -+ 0 18 -+ 1 18 -+ 2 18 -+ 3 18 -+ 4 19 -+ } -+ -+ method 'genericList ()V' { -+ 7 22 -+ 8 23 -+ 9 23 -+ a 23 -+ b 23 -+ c 23 -+ d 23 -+ e 23 -+ f 23 -+ 10 23 -+ 11 23 -+ 12 23 -+ 13 24 -+ 14 24 -+ 15 24 -+ 1d 24 -+ 1e 24 -+ 22 24 -+ 26 24 -+ 27 24 -+ 28 24 -+ 29 24 -+ 2a 24 -+ 2b 24 -+ 2c 25 -+ } -+ -+ method 'genericCast ()V' { -+ 0 28 -+ 1 28 -+ 2 28 -+ 3 28 -+ 4 28 -+ 5 28 -+ 6 28 -+ 7 29 -+ } -+ -+ method 'genericForEach ()V' { -+ 0 32 -+ 1 32 -+ 2 32 -+ 3 32 -+ 4 32 -+ 5 32 -+ 6 32 -+ 7 32 -+ d 32 -+ 20 32 -+ 21 33 -+ 22 33 -+ 23 33 -+ 24 33 -+ 25 33 -+ 26 33 -+ 27 33 -+ 2b 35 -+ } -+ -+ method 'genericForEachWithCast ()V' { -+ 0 38 -+ 1 38 -+ 2 38 -+ 3 38 -+ 4 38 -+ 5 38 -+ 6 38 -+ 7 38 -+ 8 38 -+ 9 38 -+ a 38 -+ b 38 -+ 11 38 -+ 24 38 -+ 25 39 -+ 26 39 -+ 27 39 -+ 28 39 -+ 29 39 -+ 2a 39 -+ 2b 39 -+ 2f 41 -+ } -+ -+ method 'genericSuperUp ()V' { -+ 7 44 -+ 8 46 -+ 9 46 -+ a 46 -+ 10 46 -+ 23 46 -+ 24 47 -+ 25 47 -+ 26 47 -+ 27 47 -+ 28 47 -+ 29 47 -+ 2a 47 -+ 2f 49 -+ } -+} -+ -+class 'pkg/TestGenerics$Maps' { -+ method 'newHashMap ()Ljava/util/HashMap;' { -+ 7 53 -+ } -+} -+ -+Lines mapping: -+30 <-> 15 -+31 <-> 16 -+34 <-> 19 -+35 <-> 20 -+38 <-> 23 -+39 <-> 24 -+40 <-> 25 -+41 <-> 26 -+44 <-> 29 -+45 <-> 30 -+48 <-> 33 -+49 <-> 34 -+51 <-> 36 -+54 <-> 39 -+55 <-> 40 -+57 <-> 42 -+60 <-> 45 -+61 <-> 47 -+62 <-> 48 -+64 <-> 50 -+68 <-> 54 -+Not mapped: -+50 -+56 -+63 -diff --git a/testData/results/TestKotlinConstructorKt.dec b/testData/results/TestKotlinConstructorKt.dec -index e57e91a4d0f967a12d306f22b295608a08a872f1..624026a45ae5dd4b613fb8079a0ea0743281c9cc 100644 ---- a/testData/results/TestKotlinConstructorKt.dec -+++ b/testData/results/TestKotlinConstructorKt.dec -@@ -14,8 +14,8 @@ import kotlin.collections.CollectionsKt; - ) - public final class TestKotlinConstructorKt { - private static final List foo(Collection list) { -- Iterable $receiver$iv = (Iterable)list;// 2 -- Collection destination$iv$iv = (Collection)(new ArrayList(CollectionsKt.collectionSizeOrDefault($receiver$iv, 10))); -+ Iterable $receiver$iv = list;// 2 -+ Collection destination$iv$iv = new ArrayList(CollectionsKt.collectionSizeOrDefault($receiver$iv, 10)); - - for(Object item$iv$iv : $receiver$iv) {// 10 11 - String it = (String)item$iv$iv; -@@ -24,12 +24,12 @@ public final class TestKotlinConstructorKt { - throw new TypeCastException("null cannot be cast to non-null type kotlin.String"); - } - -- var10000.((String)it); -+ var10000.(it); - Mapping var11 = var10000; - destination$iv$iv.add(var11);// 12 - } - // 4 13 -- return CollectionsKt.toList((Iterable)((List)destination$iv$iv)); -+ return CollectionsKt.toList((List)destination$iv$iv); - } - } - -diff --git a/testData/results/TestLocalsSignature.dec b/testData/results/TestLocalsSignature.dec -index 3da716bb86c538148347d67c29354a66dc416c17..3bd9c84810baa9f0cec8a62492ddccf80747d2d2 100644 ---- a/testData/results/TestLocalsSignature.dec -+++ b/testData/results/TestLocalsSignature.dec -@@ -5,7 +5,7 @@ import java.util.List; - - public class TestLocalsSignature { - public static void main(String[] args) { -- List s = new ArrayList();// 24 -+ List s = new ArrayList();// 24 - s.add("xxx");// 25 - }// 26 - } -diff --git a/testData/results/TestVarArgCalls.dec b/testData/results/TestVarArgCalls.dec -index db4cb49cc7816f05dd2e3d82a6b79a7405001e4d..89cfc1980d0ff576c6f7676da8cb8c876db2c6ae 100644 ---- a/testData/results/TestVarArgCalls.dec -+++ b/testData/results/TestVarArgCalls.dec -@@ -13,15 +13,15 @@ public class TestVarArgCalls { - String.format("Test: %d - %s", 123, "DEF");// 15 - Object[] data = new Object[]{"Hello"};// 17 - String.format("Test: %s", (Object)data);// 18 -- String.format("Test: %s", (Object[])data);// 19 -+ String.format("Test: %s", data);// 19 - }// 20 - - public void printAll(String fmt, String... params) { -- System.out.println(String.format(fmt, (Object[])params));// 23 -+ System.out.println(String.format(fmt, params));// 23 - }// 24 - - public void printComplex(String fmt, String[]... params) { -- System.out.println(String.format(fmt, (Object[])params));// 27 -+ System.out.println(String.format(fmt, params));// 27 - }// 28 - } - -diff --git a/testData/src/pkg/TestGenerics.java b/testData/src/pkg/TestGenerics.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c45ac50962a7ebbf590404070a9fbd6a6a22aa6d ---- /dev/null -+++ b/testData/src/pkg/TestGenerics.java -@@ -0,0 +1,71 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package pkg; -+ -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+ -+public class TestGenerics { -+ static Map field = Maps.newHashMap(); -+ static List> llstring = new ArrayList<>(); -+ static List bytes = new ArrayList<>(); -+ A[] aArray = (A[])(new Object[10]); -+ -+ public void genericAllocation() { -+ aArray = (A[])(new Object[20]); -+ } -+ -+ public static void genericInference() { -+ HashMap test = Maps.newHashMap(); -+ } -+ -+ public void genericList() { -+ List testList = new ArrayList(); -+ B b = testList.get(0); -+ System.out.println("B:" + b); -+ } -+ -+ public void genericCast() { -+ HashMap upcast = (HashMap)field; -+ } -+ -+ public void genericForEach() { -+ for (String s : field.keySet()) { -+ System.out.println(s); -+ } -+ } -+ -+ public void genericForEachWithCast() { -+ for (String s : llstring.get(0)) { -+ System.out.println(s); -+ } -+ } -+ -+ public void genericSuperUp() { -+ List list = new ArrayList<>(); -+ for (Number number : bytes) { -+ list.add((T)number); -+ } -+ } -+ -+ public static class Maps { -+ public static HashMap newHashMap() { -+ return new HashMap(); -+ } -+ } -+} diff --git a/FernFlower-Patches/0010-Fix-tests-for-inner-class-sorting.patch b/FernFlower-Patches/0010-Fix-tests-for-inner-class-sorting.patch new file mode 100644 index 0000000..4af74c8 --- /dev/null +++ b/FernFlower-Patches/0010-Fix-tests-for-inner-class-sorting.patch @@ -0,0 +1,486 @@ +From 4c12c7a453ab63d9b966d8247ed88e4873fe7d29 Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sun, 2 Aug 2015 19:22:15 -0700 +Subject: [PATCH 010/122] Fix tests for inner class sorting. + +--- + testData/results/TestAnonymousClass.dec | 60 ++++++++++----------- + testData/results/TestInnerLocal.dec | 50 +++++++++--------- + testData/results/TestInnerLocalPkg.dec | 50 +++++++++--------- + testData/results/TestInnerSignature.dec | 64 +++++++++++------------ + testData/results/TestMethodParameters.dec | 48 ++++++++--------- + 5 files changed, 136 insertions(+), 136 deletions(-) + +diff --git a/testData/results/TestAnonymousClass.dec b/testData/results/TestAnonymousClass.dec +index 75d1df2..fdce110 100644 +--- a/testData/results/TestAnonymousClass.dec ++++ b/testData/results/TestAnonymousClass.dec +@@ -67,15 +67,8 @@ public abstract class TestAnonymousClass { + boolean var1 = true;// 39 + }// 40 + +- static class InnerRecursive { +- TestAnonymousClass.InnerRecursive r; +- +- public InnerRecursive(TestAnonymousClass.InnerRecursive var1) { +- this.r = var1;// 105 +- }// 106 +- +- void foo() { +- }// 110 ++ interface I { ++ void foo() throws Exception; + } + + private static class Inner { +@@ -87,8 +80,15 @@ public abstract class TestAnonymousClass { + }; + } + +- interface I { +- void foo() throws Exception; ++ static class InnerRecursive { ++ TestAnonymousClass.InnerRecursive r; ++ ++ public InnerRecursive(TestAnonymousClass.InnerRecursive var1) { ++ this.r = var1;// 105 ++ }// 106 ++ ++ void foo() { ++ }// 110 + } + } + +@@ -180,24 +180,24 @@ class 'pkg/TestAnonymousClass' { + } + } + ++class 'pkg/TestAnonymousClass$Inner$1' { ++ method 'run ()V' { ++ 0 76 ++ 1 76 ++ 2 77 ++ 3 77 ++ 4 78 ++ } ++} ++ + class 'pkg/TestAnonymousClass$InnerRecursive' { + method ' (Lpkg/TestAnonymousClass$InnerRecursive;)V' { +- 6 73 +- 9 74 ++ 6 86 ++ 9 87 + } + + method 'foo ()V' { +- 0 77 +- } +-} +- +-class 'pkg/TestAnonymousClass$Inner$1' { +- method 'run ()V' { +- 0 83 +- 1 83 +- 2 84 +- 3 84 +- 4 85 ++ 0 90 + } + } + +@@ -223,9 +223,9 @@ Lines mapping: + 53 <-> 18 + 54 <-> 19 + 55 <-> 20 +-66 <-> 84 +-67 <-> 85 +-68 <-> 86 ++66 <-> 77 ++67 <-> 78 ++68 <-> 79 + 75 <-> 24 + 76 <-> 25 + 77 <-> 26 +@@ -234,9 +234,9 @@ Lines mapping: + 91 <-> 37 + 92 <-> 38 + 93 <-> 39 +-105 <-> 74 +-106 <-> 75 +-110 <-> 78 ++105 <-> 87 ++106 <-> 88 ++110 <-> 91 + Not mapped: + 18 + 104 +diff --git a/testData/results/TestInnerLocal.dec b/testData/results/TestInnerLocal.dec +index 6ca3a7e..e5aba7d 100644 +--- a/testData/results/TestInnerLocal.dec ++++ b/testData/results/TestInnerLocal.dec +@@ -28,6 +28,14 @@ public class TestInnerLocal { + new TestInnerLocal.Inner1Static.Inner2Static("test");// 40 + }// 41 + ++ class Inner1 { ++ final String x; ++ ++ public Inner1(String var2) { ++ this.x = var2;// 46 ++ }// 47 ++ } ++ + static class Inner1Static { + final String x; + +@@ -43,14 +51,6 @@ public class TestInnerLocal { + }// 60 + } + } +- +- class Inner1 { +- final String x; +- +- public Inner1(String var2) { +- this.x = var2;// 46 +- }// 47 +- } + } + + class 'TestInnerLocal$1Inner' { +@@ -84,24 +84,24 @@ class 'TestInnerLocal$2Inner' { + } + } + +-class 'TestInnerLocal$Inner1Static' { +- method ' (Ljava/lang/String;)V' { +- 6 34 +- 9 35 ++class 'TestInnerLocal$Inner1' { ++ method ' (LTestInnerLocal;Ljava/lang/String;)V' { ++ b 34 ++ e 35 + } + } + +-class 'TestInnerLocal$Inner1Static$Inner2Static' { ++class 'TestInnerLocal$Inner1Static' { + method ' (Ljava/lang/String;)V' { +- 6 41 +- 9 42 ++ 6 42 ++ 9 43 + } + } + +-class 'TestInnerLocal$Inner1' { +- method ' (LTestInnerLocal;Ljava/lang/String;)V' { +- b 50 +- e 51 ++class 'TestInnerLocal$Inner1Static$Inner2Static' { ++ method ' (Ljava/lang/String;)V' { ++ 6 49 ++ 9 50 + } + } + +@@ -119,12 +119,12 @@ Lines mapping: + 39 <-> 27 + 40 <-> 28 + 41 <-> 29 +-46 <-> 51 +-47 <-> 52 +-53 <-> 35 +-54 <-> 36 +-59 <-> 42 +-60 <-> 43 ++46 <-> 35 ++47 <-> 36 ++53 <-> 43 ++54 <-> 44 ++59 <-> 50 ++60 <-> 51 + Not mapped: + 21 + 33 +diff --git a/testData/results/TestInnerLocalPkg.dec b/testData/results/TestInnerLocalPkg.dec +index 7cafa41..7ddb0ce 100644 +--- a/testData/results/TestInnerLocalPkg.dec ++++ b/testData/results/TestInnerLocalPkg.dec +@@ -30,6 +30,14 @@ public class TestInnerLocalPkg { + new TestInnerLocalPkg.Inner1Static.Inner2Static("test");// 42 + }// 43 + ++ class Inner1 { ++ final String x; ++ ++ public Inner1(String var2) { ++ this.x = var2;// 48 ++ }// 49 ++ } ++ + static class Inner1Static { + final String x; + +@@ -45,14 +53,6 @@ public class TestInnerLocalPkg { + }// 62 + } + } +- +- class Inner1 { +- final String x; +- +- public Inner1(String var2) { +- this.x = var2;// 48 +- }// 49 +- } + } + + class 'pkg/TestInnerLocalPkg$1Inner' { +@@ -86,24 +86,24 @@ class 'pkg/TestInnerLocalPkg$2Inner' { + } + } + +-class 'pkg/TestInnerLocalPkg$Inner1Static' { +- method ' (Ljava/lang/String;)V' { +- 6 36 +- 9 37 ++class 'pkg/TestInnerLocalPkg$Inner1' { ++ method ' (Lpkg/TestInnerLocalPkg;Ljava/lang/String;)V' { ++ b 36 ++ e 37 + } + } + +-class 'pkg/TestInnerLocalPkg$Inner1Static$Inner2Static' { ++class 'pkg/TestInnerLocalPkg$Inner1Static' { + method ' (Ljava/lang/String;)V' { +- 6 43 +- 9 44 ++ 6 44 ++ 9 45 + } + } + +-class 'pkg/TestInnerLocalPkg$Inner1' { +- method ' (Lpkg/TestInnerLocalPkg;Ljava/lang/String;)V' { +- b 52 +- e 53 ++class 'pkg/TestInnerLocalPkg$Inner1Static$Inner2Static' { ++ method ' (Ljava/lang/String;)V' { ++ 6 51 ++ 9 52 + } + } + +@@ -121,12 +121,12 @@ Lines mapping: + 41 <-> 29 + 42 <-> 30 + 43 <-> 31 +-48 <-> 53 +-49 <-> 54 +-55 <-> 37 +-56 <-> 38 +-61 <-> 44 +-62 <-> 45 ++48 <-> 37 ++49 <-> 38 ++55 <-> 45 ++56 <-> 46 ++61 <-> 52 ++62 <-> 53 + Not mapped: + 23 + 35 +diff --git a/testData/results/TestInnerSignature.dec b/testData/results/TestInnerSignature.dec +index 3087a40..406e1f4 100644 +--- a/testData/results/TestInnerSignature.dec ++++ b/testData/results/TestInnerSignature.dec +@@ -9,18 +9,6 @@ public class TestInnerSignature { + this.c = var3;// 25 + }// 26 + +- public static class InnerStatic { +- A a; +- B b; +- C c; +- +- public InnerStatic(A var1, B var2, C var3) { +- this.a = var1;// 46 +- this.b = var2;// 47 +- this.c = var3;// 48 +- }// 49 +- } +- + public class Inner { + A a; + B b; +@@ -32,6 +20,18 @@ public class TestInnerSignature { + this.c = var4;// 36 + }// 37 + } ++ ++ public static class InnerStatic { ++ A a; ++ B b; ++ C c; ++ ++ public InnerStatic(A var1, B var2, C var3) { ++ this.a = var1;// 46 ++ this.b = var2;// 47 ++ this.c = var3;// 48 ++ }// 49 ++ } + } + + class 'TestInnerSignature' { +@@ -43,21 +43,21 @@ class 'TestInnerSignature' { + } + } + +-class 'TestInnerSignature$InnerStatic' { +- method ' (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { +- 6 17 +- b 18 +- 10 19 +- 13 20 ++class 'TestInnerSignature$Inner' { ++ method ' (LTestInnerSignature;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { ++ b 17 ++ 10 18 ++ 16 19 ++ 19 20 + } + } + +-class 'TestInnerSignature$Inner' { +- method ' (LTestInnerSignature;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { +- b 29 +- 10 30 +- 16 31 +- 19 32 ++class 'TestInnerSignature$InnerStatic' { ++ method ' (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' { ++ 6 29 ++ b 30 ++ 10 31 ++ 13 32 + } + } + +@@ -66,14 +66,14 @@ Lines mapping: + 24 <-> 8 + 25 <-> 9 + 26 <-> 10 +-34 <-> 30 +-35 <-> 31 +-36 <-> 32 +-37 <-> 33 +-46 <-> 18 +-47 <-> 19 +-48 <-> 20 +-49 <-> 21 ++34 <-> 18 ++35 <-> 19 ++36 <-> 20 ++37 <-> 21 ++46 <-> 30 ++47 <-> 31 ++48 <-> 32 ++49 <-> 33 + Not mapped: + 22 + 33 +diff --git a/testData/results/TestMethodParameters.dec b/testData/results/TestMethodParameters.dec +index 21f0f12..af7ce86 100644 +--- a/testData/results/TestMethodParameters.dec ++++ b/testData/results/TestMethodParameters.dec +@@ -21,6 +21,14 @@ public class TestMethodParameters { + + }// 39 + ++ class C1 { ++ C1(@Deprecated int var2) { ++ }// 24 ++ ++ void m(@Deprecated int var1) { ++ }// 25 ++ } ++ + static class C2 { + C2(@Deprecated int var1) { + }// 29 +@@ -31,14 +39,6 @@ public class TestMethodParameters { + static void m2(@Deprecated int var0) { + }// 31 + } +- +- class C1 { +- C1(@Deprecated int var2) { +- }// 24 +- +- void m(@Deprecated int var1) { +- }// 25 +- } + } + + class 'pkg/TestMethodParameters' { +@@ -69,26 +69,26 @@ class 'pkg/TestMethodParameters$1Local' { + } + } + +-class 'pkg/TestMethodParameters$C2' { +- method ' (I)V' { +- 4 25 ++class 'pkg/TestMethodParameters$C1' { ++ method ' (Lpkg/TestMethodParameters;I)V' { ++ 9 25 + } + +- method 'm1 (I)V' { ++ method 'm (I)V' { + 0 28 + } ++} + +- method 'm2 (I)V' { +- 0 31 ++class 'pkg/TestMethodParameters$C2' { ++ method ' (I)V' { ++ 4 33 + } +-} + +-class 'pkg/TestMethodParameters$C1' { +- method ' (Lpkg/TestMethodParameters;I)V' { +- 9 36 ++ method 'm1 (I)V' { ++ 0 36 + } + +- method 'm (I)V' { ++ method 'm2 (I)V' { + 0 39 + } + } +@@ -97,11 +97,11 @@ Lines mapping: + 19 <-> 5 + 20 <-> 8 + 21 <-> 11 +-24 <-> 37 +-25 <-> 40 +-29 <-> 26 +-30 <-> 29 +-31 <-> 32 ++24 <-> 26 ++25 <-> 29 ++29 <-> 34 ++30 <-> 37 ++31 <-> 40 + 36 <-> 16 + 37 <-> 19 + 39 <-> 22 +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0010-Improvements-to-var-and-var.patch b/FernFlower-Patches/0010-Improvements-to-var-and-var.patch deleted file mode 100644 index 040d37c..0000000 --- a/FernFlower-Patches/0010-Improvements-to-var-and-var.patch +++ /dev/null @@ -1,327 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Fri, 14 Apr 2017 10:13:01 -0700 -Subject: [PATCH] Improvements to var++ and var-- - - -diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -index bb2d0f0eb067a92472dcd8d69a0029d15c34c520..fde1c3bca1b12454b6f9a692c5f870ba946a590e 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java -@@ -915,7 +915,7 @@ public class NestedClassProcessor { - case Exprent.EXPRENT_FIELD -> res = classname.equals(((FieldExprent)expr).getClassname()); - case Exprent.EXPRENT_INVOCATION -> res = classname.equals(((InvocationExprent)expr).getClassName()); - case Exprent.EXPRENT_NEW -> { -- VarType newType = expr.getExprType(); -+ VarType newType = ((NewExprent)expr).getNewType(); - res = newType.getType() == CodeConstants.TYPE_OBJECT && classname.equals(newType.getValue()); - } - case Exprent.EXPRENT_VAR -> { -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java -index 81b4c480810a2f74388a4626a4dc0c2bfc523365..f0f66146eb4ecad4ed1bbd41712cace8fe466ed5 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java -@@ -14,18 +14,15 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; - import org.jetbrains.java.decompiler.struct.gen.VarType; - --import java.util.HashMap; - import java.util.HashSet; - import java.util.LinkedList; - import java.util.List; --import java.util.Map; --import java.util.Objects; - - public class PPandMMHelper { - - private boolean exprentReplaced; - private VarProcessor varProc; -- private Map remaps = new HashMap<>(); -+ private DirectGraph dgraph; - - public PPandMMHelper(VarProcessor varProc) { - this.varProc = varProc; -@@ -34,10 +31,10 @@ public class PPandMMHelper { - public boolean findPPandMM(RootStatement root) { - - FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); -- DirectGraph dgraph = flatthelper.buildDirectGraph(root); -+ this.dgraph = flatthelper.buildDirectGraph(root); - - LinkedList stack = new LinkedList<>(); -- stack.add(dgraph.first); -+ stack.add(this.dgraph.first); - - HashSet setVisited = new HashSet<>(); - -@@ -57,8 +54,6 @@ public class PPandMMHelper { - stack.addAll(node.successors); - } - -- updateVersions(dgraph); -- - return res; - } - -@@ -133,7 +128,7 @@ public class PPandMMHelper { - if (econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) { - Exprent left = as.getLeft(); - -- VarType condtype = econd.getExprType(); -+ VarType condtype = left.getExprType(); - if (exprsEqual(left, econd) && (midlayer == null || midlayer.equals(condtype))) { - FunctionExprent ret = new FunctionExprent( - func.getFuncType() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI, -@@ -143,7 +138,7 @@ public class PPandMMHelper { - exprentReplaced = true; - - if (!left.equals(econd)) { -- remaps.put(new VarVersionPair((VarExprent)left), new VarVersionPair((VarExprent)econd)); -+ updateVersions(this.dgraph, new VarVersionPair((VarExprent)left), new VarVersionPair((VarExprent)econd)); - } - - return ret; -@@ -171,13 +166,13 @@ public class PPandMMHelper { - - VarExprent v1 = (VarExprent)e1; - VarExprent v2 = (VarExprent)e2; -- return varProc.getVarOriginalIndex(v1.getIndex()) == varProc.getVarOriginalIndex(v2.getIndex()) -- && Objects.equals(v1.getVarType(), v2.getVarType()); -+ return varProc.getVarOriginalIndex(v1.getIndex()) == varProc.getVarOriginalIndex(v2.getIndex()); -+ // TODO: Verify the types are in the same 'family' {byte->short->int} -+ // && Objects.equals(v1.getVarType(), v2.getVarType()); - } - - -- private void updateVersions(DirectGraph graph) { -- if (remaps.isEmpty()) return; -+ private void updateVersions(DirectGraph graph, final VarVersionPair oldVVP, final VarVersionPair newVVP) { - graph.iterateExprents(new DirectGraph.ExprentIterator() { - @Override - public int processExprent(Exprent exprent) { -@@ -187,10 +182,9 @@ public class PPandMMHelper { - for (Exprent expr : lst) { - if (expr.type == Exprent.EXPRENT_VAR) { - VarExprent var = (VarExprent)expr; -- VarVersionPair nvar = remaps.get(new VarVersionPair(var)); -- if (nvar != null) { -- var.setIndex(nvar.var); -- var.setVersion(nvar.version); -+ if (var.getIndex() == oldVVP.var && var.getVersion() == oldVVP.version) { -+ var.setIndex(newVVP.var); -+ var.setVersion(newVVP.version); - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -index b0bda600031b4cc52b6b083d5afd07a92ccef1af..401917e6947c0ae541c966777cf2deddf54ed644 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java -@@ -500,7 +500,12 @@ public class ConstExprent extends Exprent { - public void getBytecodeRange(BitSet values) { - measureBytecode(values); - } -- -+ -+ @Override -+ public String toString() { -+ return "const(" + toJava(0, new BytecodeMappingTracer()) + ")"; -+ } -+ - // ***************************************************************************** - // IMatchable implementation - // ***************************************************************************** -diff --git a/test/org/jetbrains/java/decompiler/LVTTest.java b/test/org/jetbrains/java/decompiler/LVTTest.java -index 388e1facddbac3286eaed3dbccc3b23197daf5d6..6ffaa0f8581c48b4fd2f96d0c21368d63e69cf5f 100644 ---- a/test/org/jetbrains/java/decompiler/LVTTest.java -+++ b/test/org/jetbrains/java/decompiler/LVTTest.java -@@ -46,4 +46,5 @@ public class LVTTest extends SingleClassesTestBase { - @Test public void testLVTComplex() { doTest("pkg/TestLVTComplex"); } - @Test public void testVarType() { doTest("pkg/TestVarType"); } - @Test public void testLoopMerging() { doTest("pkg/TestLoopMerging"); } -+ @Test public void testPPMM() { doTest("pkg/TestPPMM"); } - } -diff --git a/testData/classes/pkg/TestPPMM.class b/testData/classes/pkg/TestPPMM.class -new file mode 100644 -index 0000000000000000000000000000000000000000..8caf72506e9847d87715ffb7804ba9538aea668f -GIT binary patch -literal 1271 -zcmb8u+ins;9LMqBEVL+6ig>66Db{$PR*M()lwvhjYfz{pHuZYJ6}NH -z+A#`mwBLJ1vn9XfZS6O!UU%EAHfTwf+BLVa<92;pA2x=2AN@U}c&YQLp5ONNdX-AK -zyhbj+(=jqGPmx-uDx)n -z{54i~-Op}JQ<{$HqUMZZM`vJ^u>JXl+p6c^RCm2vPm3%%%ukS_GIk(kgj$|xh*P(| -z$$aI-(J4yXEhTlDGB)^tfoG^;jRwD?=Fm19DjXOyy8op~@u`@hqdCk=q@E{9N^zz8 -zscjF#hp8RSaK%Z=4xALpkZJ)W3vvZykwjM~AcF* +Date: Sun, 2 Aug 2015 19:49:30 -0700 +Subject: [PATCH 011/122] Fixed issue where field initalizers would incorrectly + be inlined when they relied on fields initalized later. + +--- + .../decompiler/main/InitializerProcessor.java | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +index d916b19..e64feea 100644 +--- a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java ++++ b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +@@ -142,9 +142,8 @@ public class InitializerProcessor { + if (fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) && + cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) { + +- if (isExprentIndependent(asexpr.getRight(), meth, cl, whitelist)) { +- +- String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString); ++ String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString); ++ if (isExprentIndependent(asexpr.getRight(), meth, cl, whitelist, cl.getFields().getIndexByKey(keyField))) { + if (!wrapper.getStaticFieldInitializers().containsKey(keyField)) { + wrapper.getStaticFieldInitializers().addWithKey(asexpr.getRight(), keyField); + whitelist.add(keyField); +@@ -217,8 +216,8 @@ public class InitializerProcessor { + cl.hasField(fexpr.getName(), fexpr + .getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass. + +- if (isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i), cl, whitelist)) { +- String fieldKey = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString); ++ String fieldKey = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString); ++ if (isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i), cl, whitelist, cl.getFields().getIndexByKey(fieldKey))) { + if (fieldWithDescr == null) { + fieldWithDescr = fieldKey; + value = asexpr.getRight(); +@@ -253,7 +252,7 @@ public class InitializerProcessor { + } + } + +- private static boolean isExprentIndependent(Exprent exprent, MethodWrapper meth, StructClass cl, Set whitelist) { ++ private static boolean isExprentIndependent(Exprent exprent, MethodWrapper meth, StructClass cl, Set whitelist, int fidx) { + + List lst = exprent.getAllExprents(true); + lst.add(exprent); +@@ -273,9 +272,11 @@ public class InitializerProcessor { + case Exprent.EXPRENT_FIELD: + FieldExprent fexpr = (FieldExprent)expr; + if (cl.qualifiedName.equals(fexpr.getClassname())) { +- if (!whitelist.contains(InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString))) { ++ String key = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString); ++ if (!whitelist.contains(key)) { + return false; + } ++ return cl.getFields().getIndexByKey(key) < fidx; + } + else if (!fexpr.isStatic()) { + return false; +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0011-JAD-Style-variable-naming.patch b/FernFlower-Patches/0011-JAD-Style-variable-naming.patch deleted file mode 100644 index 1a30eab..0000000 --- a/FernFlower-Patches/0011-JAD-Style-variable-naming.patch +++ /dev/null @@ -1,981 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Tue, 11 Apr 2017 22:37:40 -0700 -Subject: [PATCH] JAD Style variable naming - - -diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java -index 31236841f1b4bf4f452f30d6b95f21fcc99ec5b9..aa990406ef8d91838aa2d928bdfb183fe9e19333 100644 ---- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java -+++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java -@@ -117,15 +117,20 @@ public class ClassWriter { - buffer.append(", "); - } - -+ List iParameterTypeAnnotations = TargetInfo.FormalParameterTarget.extract(parameterTypeAnnotations, i); -+ VarType type = md_content.params[i]; -+ String typeName = ExprProcessor.getCastTypeName(type, explicitlyTyped, TypeAnnotationWriteHelper.create(iParameterTypeAnnotations)); - if (explicitlyTyped) { -- List iParameterTypeAnnotations = TargetInfo.FormalParameterTarget.extract(parameterTypeAnnotations, i); -- VarType type = md_content.params[i]; -- buffer.append(ExprProcessor.getCastTypeName(type, TypeAnnotationWriteHelper.create(iParameterTypeAnnotations))); -+ buffer.append(typeName); - buffer.append(' '); - } - - String parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0)); -- buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors -+ if (parameterName == null) { -+ parameterName = "param" + index; // null iff decompiled with errors -+ } -+ parameterName = methodWrapper.methodStruct.getVariableNamer().renameParameter(mt.getAccessFlags(), typeName, parameterName, index); -+ buffer.append(parameterName); - - firstParameter = false; - } -@@ -747,7 +752,11 @@ public class ClassWriter { - buffer.append(' '); - - String parameterName = methodWrapper.varproc.getVarName(pair); -- buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors -+ if (parameterName == null) { -+ parameterName = "param" + index; // null iff decompiled with errors -+ } -+ parameterName = methodWrapper.methodStruct.getVariableNamer().renameParameter(flags, typeName, parameterName, index); -+ buffer.append(parameterName); - - paramCount++; - } -@@ -919,7 +928,11 @@ public class ClassWriter { - buffer.append(" "); - - String parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0)); -- buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors -+ if (parameterName == null) { -+ parameterName = "param" + index; // null iff decompiled with errors -+ } -+ parameterName = methodWrapper.methodStruct.getVariableNamer().renameParameter(mt.getAccessFlags(), typeName, parameterName, index); -+ buffer.append(parameterName); - - firstParameter = false; - } -diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -index 8173ecd04da97e5e9a8f5f9a2e309726439697e0..3398f884985021a324fc5ae6ac6a461f8e5b2f33 100644 ---- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -+++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java -@@ -146,6 +146,7 @@ public class ClassesProcessor implements CodeConstants { - node.access = cl.getAccessFlags(); - mapRootClasses.put(cl.qualifiedName, node); - } -+ linkEnclosingMethods(cl); - } - - // set non-sealed if class extends or implements a sealed class and is not final or sealed itself -@@ -256,6 +257,25 @@ public class ClassesProcessor implements CodeConstants { - } - } - -+ private void linkEnclosingMethods(StructClass cl) { -+ StructEnclosingMethodAttribute attr = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_ENCLOSING_METHOD); -+ if (attr == null || attr.getMethodName() == null) { -+ return; -+ } -+ StructClass parent = context.getClasses().get(attr.getClassName()); -+ if (parent == null) { -+ return; -+ } -+ StructMethod method = parent.getMethod(attr.getMethodName(), attr.getMethodDescriptor()); -+ if (method == null) { -+ return; -+ } -+ if (method.enclosedClasses == null) { -+ method.enclosedClasses = new HashSet<>(); -+ } -+ method.enclosedClasses.add(cl.qualifiedName); -+ } -+ - private static boolean isAnonymous(StructClass cl, StructClass enclosingCl) { - // checking super class and interfaces - int[] interfaces = cl.getInterfaces(); -@@ -441,6 +461,7 @@ public class ClassesProcessor implements CodeConstants { - private static void destroyWrappers(ClassNode node) { - node.wrapper = null; - node.classStruct.releaseResources(); -+ node.classStruct.getMethods().forEach(m -> m.clearVariableNamer()); - - for (ClassNode nd : node.nested) { - destroyWrappers(nd); -@@ -563,4 +584,4 @@ public class ClassesProcessor implements CodeConstants { - public boolean is_content_method_static; - } - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java -index 654d0ddf34821ce4ea800cd5421f6268e2ca3236..bb7b5b4e4a590219939a8f7e883b9c259c1adf73 100644 ---- a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java -+++ b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java -@@ -7,6 +7,7 @@ import org.jetbrains.java.decompiler.main.collectors.ImportCollector; - import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; - import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; -+import org.jetbrains.java.decompiler.main.extern.IVariableNamingFactory; - import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor; - import org.jetbrains.java.decompiler.struct.StructContext; - -@@ -20,12 +21,14 @@ public class DecompilerContext { - public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER"; - public static final String CURRENT_VAR_PROCESSOR = "CURRENT_VAR_PROCESSOR"; - public static final String IN_CLASS_TYPE_PARAMS = "IN_CLASS_TYPE_PARAMS"; -+ public static final String RENAMER_FACTORY = "RENAMER_FACTORY"; - - private final Map properties; - private final IFernflowerLogger logger; - private final StructContext structContext; - private final ClassesProcessor classProcessor; - private final PoolInterceptor poolInterceptor; -+ private final IVariableNamingFactory renamerFactory; - private ImportCollector importCollector; - private VarProcessor varProcessor; - private CounterContainer counterContainer; -@@ -35,7 +38,8 @@ public class DecompilerContext { - IFernflowerLogger logger, - StructContext structContext, - ClassesProcessor classProcessor, -- PoolInterceptor interceptor) { -+ PoolInterceptor interceptor, -+ IVariableNamingFactory renamerFactory) { - Objects.requireNonNull(properties); - Objects.requireNonNull(logger); - Objects.requireNonNull(structContext); -@@ -46,6 +50,7 @@ public class DecompilerContext { - this.structContext = structContext; - this.classProcessor = classProcessor; - this.poolInterceptor = interceptor; -+ this.renamerFactory = renamerFactory; - this.counterContainer = new CounterContainer(); - } - -@@ -113,6 +118,10 @@ public class DecompilerContext { - return getCurrentContext().poolInterceptor; - } - -+ public static IVariableNamingFactory getNamingFactory() { -+ return getCurrentContext().renamerFactory; -+ } -+ - public static ImportCollector getImportCollector() { - return getCurrentContext().importCollector; - } -diff --git a/src/org/jetbrains/java/decompiler/main/Fernflower.java b/src/org/jetbrains/java/decompiler/main/Fernflower.java -index f8c413c7b7302b201a739310677d0103e2878d3e..aa8b1132b84fc44bf6decd96ebaf5c021c185ac1 100644 ---- a/src/org/jetbrains/java/decompiler/main/Fernflower.java -+++ b/src/org/jetbrains/java/decompiler/main/Fernflower.java -@@ -10,6 +10,7 @@ import org.jetbrains.java.decompiler.struct.IDecompiledData; - import org.jetbrains.java.decompiler.struct.StructClass; - import org.jetbrains.java.decompiler.struct.StructContext; - import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; -+import org.jetbrains.java.decompiler.util.JADNameProvider; - import org.jetbrains.java.decompiler.util.TextBuffer; - import org.jetbrains.java.decompiler.util.ClasspathScanner; - -@@ -52,7 +53,25 @@ public class Fernflower implements IDecompiledData { - converter = null; - } - -- DecompilerContext context = new DecompilerContext(properties, logger, structContext, classProcessor, interceptor); -+ IVariableNamingFactory renamerFactory = null; -+ String factoryClazz = (String) properties.get(DecompilerContext.RENAMER_FACTORY); -+ if (factoryClazz != null) { -+ try { -+ renamerFactory = Class.forName(factoryClazz).asSubclass(IVariableNamingFactory.class).getDeclaredConstructor().newInstance(); -+ } catch (Exception e) { -+ logger.writeMessage("Error loading renamer factory class: " + factoryClazz, e); -+ } -+ } -+ if (renamerFactory == null) { -+ if("1".equals(properties.get(IFernflowerPreferences.USE_JAD_VARNAMING))) { -+ boolean renameParams = "1".equals(properties.get(IFernflowerPreferences.USE_JAD_PARAMETER_RENAMING)); -+ renamerFactory = new JADNameProvider.JADNameProviderFactory(renameParams); -+ } else { -+ renamerFactory = new IdentityRenamerFactory(); -+ } -+ } -+ -+ DecompilerContext context = new DecompilerContext(properties, logger, structContext, classProcessor, interceptor, renamerFactory); - DecompilerContext.setCurrentContext(context); - - String vendor = System.getProperty("java.vendor", "missing vendor"); -diff --git a/src/org/jetbrains/java/decompiler/main/IdentityRenamerFactory.java b/src/org/jetbrains/java/decompiler/main/IdentityRenamerFactory.java -new file mode 100644 -index 0000000000000000000000000000000000000000..872ec764f11131d384e59f08c4aac9551add771b ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/main/IdentityRenamerFactory.java -@@ -0,0 +1,39 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler.main; -+ -+import java.util.Map; -+ -+import org.jetbrains.java.decompiler.main.extern.IVariableNameProvider; -+import org.jetbrains.java.decompiler.main.extern.IVariableNamingFactory; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -+import org.jetbrains.java.decompiler.struct.StructMethod; -+ -+public class IdentityRenamerFactory implements IVariableNamingFactory, IVariableNameProvider { -+ @Override -+ public IVariableNameProvider createFactory(StructMethod method) { -+ return this; -+ } -+ -+ @Override -+ public Map rename(Map variables) { -+ return null; -+ } -+ -+ @Override -+ public void addParentContext(IVariableNameProvider renamer) { -+ } -+} -diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -index 79108dd8772dc9444d66e6ba0cdd7f56ca382fbd..3cbbb19b4dd705f67d0b2450996f704a9e293168 100644 ---- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -+++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -@@ -52,6 +52,9 @@ public interface IFernflowerPreferences { - String LINE_SEPARATOR_WIN = "\r\n"; - String LINE_SEPARATOR_UNX = "\n"; - -+ String USE_JAD_VARNAMING = "jvn"; // Overwrites any Local Variable names with JAD style names -+ String USE_JAD_PARAMETER_RENAMING = "jpr"; // Include parameter names in JAD naming -+ - Map DEFAULTS = getDefaults(); - - static Map getDefaults() { -@@ -95,7 +98,9 @@ public interface IFernflowerPreferences { - defaults.put(BANNER, ""); - defaults.put(UNIT_TEST_MODE, "0"); - defaults.put(DUMP_ORIGINAL_LINES, "0"); -+ defaults.put(USE_JAD_VARNAMING, "0"); -+ defaults.put(USE_JAD_PARAMETER_RENAMING, "0"); - - return Collections.unmodifiableMap(defaults); - } --} -\ No newline at end of file -+} -diff --git a/src/org/jetbrains/java/decompiler/main/extern/IVariableNameProvider.java b/src/org/jetbrains/java/decompiler/main/extern/IVariableNameProvider.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0c47d21eef640037a0c8ce69d9b4d5815be9ccd9 ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/main/extern/IVariableNameProvider.java -@@ -0,0 +1,37 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler.main.extern; -+ -+import java.util.Map; -+ -+import org.jetbrains.java.decompiler.code.CodeConstants; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -+ -+public interface IVariableNameProvider { -+ public Map rename(Map variables); -+ -+ default String renameAbstractParameter(String name, int index) { -+ return name; -+ } -+ -+ default String renameParameter(int flags, String type, String name, int index) { -+ if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) -+ return renameAbstractParameter(name, index); -+ return name; -+ } -+ -+ public void addParentContext(IVariableNameProvider renamer); -+} -diff --git a/src/org/jetbrains/java/decompiler/main/extern/IVariableNamingFactory.java b/src/org/jetbrains/java/decompiler/main/extern/IVariableNamingFactory.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fc1d7d67864ab12e894fcdf0ed8e1297ce057bee ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/main/extern/IVariableNamingFactory.java -@@ -0,0 +1,22 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler.main.extern; -+ -+import org.jetbrains.java.decompiler.struct.StructMethod; -+ -+public interface IVariableNamingFactory { -+ public IVariableNameProvider createFactory(StructMethod structMethod); -+} -diff --git a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -index c1126a2b7559e2f8a69a54ee0b7db2ceda3d9776..964bff5a00b35969fa08e48ca355801fe2882ce8 100644 ---- a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -+++ b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java -@@ -158,7 +158,8 @@ public class ClassWrapper { - } - - private static void applyDebugInfo(StructMethod mt, VarProcessor varProc, MethodWrapper methodWrapper) { -- if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) { -+ // Only rename parameters in the var processor if we aren't already renaming them with JAD naming -+ if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES) && (!DecompilerContext.getOption(IFernflowerPreferences.USE_JAD_VARNAMING) || !DecompilerContext.getOption(IFernflowerPreferences.USE_JAD_PARAMETER_RENAMING))) { - StructLocalVariableTableAttribute attr = mt.getLocalVariableAttr(); - if (attr != null) { - // only param names here -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -index f9a7e55c108959b9696cb52cfd91aee341e40b06..b35985211d1f0488f76cbd6e87f18e3732b2d589 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java -@@ -2,6 +2,7 @@ - package org.jetbrains.java.decompiler.modules.decompiler.vars; - - import org.jetbrains.java.decompiler.code.CodeConstants; -+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; - import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector; - import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; -@@ -11,6 +12,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent; -+import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent; - import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; - import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement; - import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement; -@@ -25,6 +27,7 @@ import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribu - import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; - import org.jetbrains.java.decompiler.struct.gen.VarType; - import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; -+import org.jetbrains.java.decompiler.util.StatementIterator; - - import java.util.*; - import java.util.Map.Entry; -@@ -842,6 +845,53 @@ public class VarDefinitionHelper { - for (Entry e : types.entrySet()) { - typeNames.put(e.getKey(), e.getValue().getCast()); - } -+ -+ Map renames = this.mt.getVariableNamer().rename(typeNames); -+ -+ // Stuff the parent context into enclosed child methods -+ StatementIterator.iterate(root, (exprent) -> { -+ List methods = new ArrayList<>(); -+ if (exprent.type == Exprent.EXPRENT_VAR) { -+ VarExprent var = (VarExprent)exprent; -+ if (var.isClassDef()) { -+ ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(var.getVarType().getValue()); -+ if (child != null) -+ methods.addAll(child.classStruct.getMethods()); -+ } -+ } -+ else if (exprent.type == Exprent.EXPRENT_NEW) { -+ NewExprent _new = (NewExprent)exprent; -+ if (_new.isAnonymous()) { //TODO: Check for Lambda here? -+ ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(_new.getNewType().getValue()); -+ if (child != null) { -+ if (_new.isLambda()) { -+ if (child.lambdaInformation.is_method_reference) { -+ //methods.add(child.getWrapper().getClassStruct().getMethod(child.lambdaInformation.content_method_key)); -+ } else { -+ methods.add(child.classStruct.getMethod(child.lambdaInformation.content_method_name, child.lambdaInformation.content_method_descriptor)); -+ } -+ } else { -+ methods.addAll(child.classStruct.getMethods()); -+ } -+ } -+ } -+ } -+ -+ for (StructMethod meth : methods) { -+ meth.getVariableNamer().addParentContext(VarDefinitionHelper.this.mt.getVariableNamer()); -+ } -+ return 0; -+ }); -+ -+ if (mt.enclosedClasses != null) { -+ for (String cls : mt.enclosedClasses) { -+ StructClass cl = DecompilerContext.getStructContext().getClass(cls); -+ for (StructMethod meth : cl.getMethods()) { -+ meth.getVariableNamer().addParentContext(this.mt.getVariableNamer()); -+ } -+ } -+ } -+ - Map lvts = new HashMap<>(); - - for (Entry e : types.entrySet()) { -@@ -851,7 +901,16 @@ public class VarDefinitionHelper { - continue; - } - LocalVariable lvt = e.getValue().getLVT(); -+ String rename = renames == null ? null : renames.get(idx); -+ -+ if (rename != null) { -+ varproc.setVarName(idx, rename); -+ } -+ - if (lvt != null) { -+ if (rename != null) { -+ lvt = lvt.rename(rename); -+ } - varproc.setVarLVT(idx, lvt); - lvts.put(idx, lvt); - } -@@ -985,7 +1044,7 @@ public class VarDefinitionHelper { - - private VarInfo(LocalVariable lvt, VarType type) { - if (lvt != null && lvt.getSignature() != null) -- this.cast = ExprProcessor.getCastTypeName(GenericType.parse(lvt.getSignature()), true, Collections.emptyList()); -+ this.cast = ExprProcessor.getCastTypeName(GenericType.parse(lvt.getSignature()), false, Collections.emptyList()); - else if (lvt != null) - this.cast = ExprProcessor.getCastTypeName(lvt.getVarType(), false, Collections.emptyList()); - else if (type != null) -diff --git a/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/src/org/jetbrains/java/decompiler/struct/StructMethod.java -index d48e950e7511d2a00ac9885d5dc7d4ff524bbb37..08efdbaa173380dbbc0cd30c5ec5d43b0c2cf074 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructMethod.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructMethod.java -@@ -4,6 +4,7 @@ package org.jetbrains.java.decompiler.struct; - import org.jetbrains.java.decompiler.code.*; - import org.jetbrains.java.decompiler.main.DecompilerContext; - import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; -+import org.jetbrains.java.decompiler.main.extern.IVariableNameProvider; - import org.jetbrains.java.decompiler.struct.attr.StructCodeAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; - import org.jetbrains.java.decompiler.struct.attr.StructGenericSignatureAttribute; -@@ -20,6 +21,7 @@ import java.io.IOException; - import java.util.ArrayList; - import java.util.List; - import java.util.Map; -+import java.util.Set; - - import static org.jetbrains.java.decompiler.code.CodeConstants.*; - -@@ -72,6 +74,8 @@ public class StructMethod extends StructMember { - private boolean expanded = false; - private final String classQualifiedName; - private final GenericMethodDescriptor signature; -+ private IVariableNameProvider renamer; -+ public Set enclosedClasses; // Dirty hack, but the management of nested classes is trash. - - private StructMethod(int accessFlags, - Map attributes, -@@ -338,6 +342,17 @@ public class StructMethod extends StructMember { - return seq; - } - -+ public IVariableNameProvider getVariableNamer() { -+ if (renamer == null) { -+ this.renamer = DecompilerContext.getNamingFactory().createFactory(this); -+ } -+ return renamer; -+ } -+ -+ public void clearVariableNamer() { -+ this.renamer = null; -+ } -+ - public StructLocalVariableTableAttribute getLocalVariableAttr() { - return getAttribute(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE); - } -diff --git a/src/org/jetbrains/java/decompiler/util/JADNameProvider.java b/src/org/jetbrains/java/decompiler/util/JADNameProvider.java -new file mode 100644 -index 0000000000000000000000000000000000000000..15d798679efb2b6a14d93e665a5e2a2e1bc64102 ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/util/JADNameProvider.java -@@ -0,0 +1,228 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler.util; -+ -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.LinkedHashMap; -+import java.util.List; -+import java.util.Locale; -+import java.util.Map; -+import java.util.Map.Entry; -+import java.util.regex.Pattern; -+import java.util.stream.Collectors; -+ -+import org.jetbrains.java.decompiler.code.CodeConstants; -+import org.jetbrains.java.decompiler.main.extern.IVariableNameProvider; -+import org.jetbrains.java.decompiler.main.extern.IVariableNamingFactory; -+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -+import org.jetbrains.java.decompiler.struct.StructMethod; -+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; -+import org.jetbrains.java.decompiler.struct.gen.VarType; -+ -+public class JADNameProvider implements IVariableNameProvider { -+ private HashMap last = null; -+ private HashMap remap = null; -+ private final HashMap parameters = new HashMap<>(); -+ private final StructMethod method; -+ private final boolean renameParameters; -+ private static final Pattern CAPS_START = Pattern.compile("^[A-Z]"); -+ private static final Pattern ARRAY = Pattern.compile("(\\[|\\.\\.\\.)"); -+ -+ public JADNameProvider(boolean renameParameters, StructMethod wrapper) { -+ last = new HashMap<>(); -+ last.put("int", new Holder(0, true, "i", "j", "k", "l")); -+ last.put("byte", new Holder(0, false, "b" )); -+ last.put("char", new Holder(0, false, "c" )); -+ last.put("short", new Holder(1, false, "short" )); -+ last.put("boolean", new Holder(0, true, "flag" )); -+ last.put("double", new Holder(0, false, "d" )); -+ last.put("float", new Holder(0, true, "f" )); -+ last.put("File", new Holder(1, true, "file" )); -+ last.put("String", new Holder(0, true, "s" )); -+ last.put("Class", new Holder(0, true, "oclass" )); -+ last.put("Long", new Holder(0, true, "olong" )); -+ last.put("Byte", new Holder(0, true, "obyte" )); -+ last.put("Short", new Holder(0, true, "oshort" )); -+ last.put("Boolean", new Holder(0, true, "obool" )); -+ last.put("Package", new Holder(0, true, "opackage")); -+ last.put("Enum", new Holder(0, true, "oenum" )); -+ -+ remap = new HashMap<>(); -+ remap.put("long", "int"); -+ -+ this.method = wrapper; -+ this.renameParameters = renameParameters; -+ } -+ -+ @Override -+ public synchronized void addParentContext(IVariableNameProvider iparent) { -+ JADNameProvider parent = (JADNameProvider) iparent; -+ HashMap temp = new HashMap<>(); -+ for (Entry e : parent.last.entrySet()) { -+ temp.put(e.getKey(), e.getValue().copy()); -+ } -+ this.last = temp; -+ this.remap = new HashMap<>(parent.remap); -+ } -+ -+ private static class Holder { -+ public int id; -+ public boolean skip_zero; -+ public final List names = new ArrayList<>(); -+ -+ public Holder(int t1, boolean skip_zero, String... names) { -+ this.id = t1; -+ this.skip_zero = skip_zero; -+ Collections.addAll(this.names, names); -+ } -+ -+ public Holder(int t1, boolean skip_zero, List names) { -+ this.id = t1; -+ this.skip_zero = skip_zero; -+ this.names.addAll(names); -+ } -+ -+ @Override -+ public String toString() { -+ return "Holder[" + id + ", " + skip_zero + ", " + names.stream().collect(Collectors.joining(", ")) + "]"; -+ } -+ -+ public Holder copy() { -+ return new Holder(this.id, this.skip_zero, new ArrayList<>(this.names)); -+ } -+ } -+ -+ @Override -+ public Map rename(Map entries) { -+ int params = 0; -+ if ((this.method.getAccessFlags() & CodeConstants.ACC_STATIC) != CodeConstants.ACC_STATIC) { -+ params++; -+ } -+ -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(this.method.getDescriptor()); -+ for (VarType param : md.params) { -+ params += param.getStackSize(); -+ } -+ -+ List keys = new ArrayList<>(entries.keySet()); -+ Collections.sort(keys, (o1, o2) -> (o1.var != o2.var) ? o1.var - o2.var : o1.version - o2.version); -+ -+ Map result = new LinkedHashMap<>(); -+ for (VarVersionPair ver : keys) { -+ String type = cleanType(entries.get(ver)); -+ if ("this".equals(type)) { -+ continue; -+ } -+ if (ver.var >= params) { -+ result.put(ver, getNewName(type)); -+ } else if (renameParameters) { -+ result.put(ver, this.parameters.computeIfAbsent(ver.var, k -> getNewName(type))); -+ } -+ } -+ return result; -+ } -+ -+ private String cleanType(String type) { -+ if (type.indexOf('<') != -1) { -+ type = type.substring(0, type.indexOf('<')); -+ } -+ if (type.indexOf('.') != -1) { -+ type = type.substring(type.lastIndexOf('.') + 1); -+ } -+ return type; -+ } -+ -+ protected synchronized String getNewName(String type) { -+ String index = null; -+ String findtype = type; -+ -+ while (findtype.contains("[][]")) { -+ findtype = findtype.replaceAll("\\[\\]\\[\\]", "[]"); -+ } -+ if (last.containsKey(findtype)) { -+ index = findtype; -+ } -+ else if (last.containsKey(findtype.toLowerCase(Locale.ENGLISH))) { -+ index = findtype.toLowerCase(Locale.ENGLISH); -+ } -+ else if (remap.containsKey(type)) { -+ index = remap.get(type); -+ } -+ -+ if ((index == null || index.length() == 0) && (CAPS_START.matcher(type).find() || ARRAY.matcher(type).find())) { // replace multi things with arrays. -+ type = type.replace("...", "[]"); -+ -+ while (type.contains("[][]")) { -+ type = type.replaceAll("\\[\\]\\[\\]", "[]"); -+ } -+ -+ String name = type.toLowerCase(Locale.ENGLISH); -+ // Strip single dots that might happen because of inner class references -+ name = name.replace(".", ""); -+ boolean skip_zero = true; -+ -+ if (Pattern.compile("\\[").matcher(type).find()) { -+ skip_zero = true; -+ name = "a" + name.replace("[]", "").replace("...", ""); -+ } -+ -+ last.put(type.toLowerCase(Locale.ENGLISH), new Holder(0, skip_zero, name)); -+ index = type.toLowerCase(Locale.ENGLISH); -+ } -+ -+ if (index == null || index.length() == 0) { -+ return type.toLowerCase(Locale.ENGLISH); -+ } -+ -+ Holder holder = last.get(index); -+ int id = holder.id; -+ List names = holder.names; -+ -+ int ammount = names.size(); -+ -+ String name; -+ if (ammount == 1) { -+ name = names.get(0) + (id == 0 && holder.skip_zero ? "" : id); -+ } -+ else { -+ int num = id / ammount; -+ name = names.get(id % ammount) + (id < ammount && holder.skip_zero ? "" : num); -+ } -+ -+ holder.id++; -+ return name; -+ } -+ -+ @Override -+ public String renameParameter(int flags, String type, String name, int index) { -+ if (!this.renameParameters) -+ return IVariableNameProvider.super.renameParameter(flags, type, name, index); -+ return this.parameters.computeIfAbsent(index, k -> getNewName(cleanType(type))); -+ } -+ -+ public static class JADNameProviderFactory implements IVariableNamingFactory { -+ private final boolean renameParameters; -+ public JADNameProviderFactory(boolean renameParameters) { -+ this.renameParameters = renameParameters; -+ } -+ @Override -+ public IVariableNameProvider createFactory(StructMethod method) { -+ return new JADNameProvider(renameParameters, method); -+ } -+ } -+} -diff --git a/src/org/jetbrains/java/decompiler/util/StatementIterator.java b/src/org/jetbrains/java/decompiler/util/StatementIterator.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a41c910e58c3c0e16e6b13a90fe9f34acea09662 ---- /dev/null -+++ b/src/org/jetbrains/java/decompiler/util/StatementIterator.java -@@ -0,0 +1,58 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler.util; -+ -+import java.util.List; -+ -+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; -+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph.ExprentIterator; -+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; -+ -+public class StatementIterator { -+ public static void iterate(Statement stat, ExprentIterator itr) { -+ if (stat == null) { -+ return; -+ } -+ -+ for (Exprent exp : stat.getVarDefinitions()) { -+ iterate(exp, itr); -+ } -+ -+ if (stat.getExprents() == null) { -+ for (Object obj : stat.getSequentialObjects()) { -+ if (obj instanceof Statement) { -+ iterate((Statement)obj, itr); -+ } -+ else if (obj instanceof Exprent) { -+ iterate((Exprent)obj, itr); -+ } -+ } -+ } -+ else { -+ for (Exprent exp : stat.getExprents()) { -+ iterate(exp, itr); -+ } -+ } -+ } -+ -+ private static void iterate(Exprent exp, ExprentIterator itr) { -+ List lst = exp.getAllExprents(true); -+ lst.add(exp); -+ for (Exprent exprent : lst) { -+ itr.processExprent(exprent); -+ } -+ } -+} -diff --git a/test/org/jetbrains/java/decompiler/JADTest.java b/test/org/jetbrains/java/decompiler/JADTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5348637179299ad07934495be8216583da36897b ---- /dev/null -+++ b/test/org/jetbrains/java/decompiler/JADTest.java -@@ -0,0 +1,36 @@ -+/* -+ * Copyright 2000-2017 JetBrains s.r.o. -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package org.jetbrains.java.decompiler; -+ -+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; -+import org.junit.Test; -+ -+import java.util.Map; -+ -+public class JADTest extends SingleClassesTestBase { -+ -+ @Override -+ protected Map getDecompilerOptions() { -+ return Map.of( -+ IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", -+ IFernflowerPreferences.DUMP_ORIGINAL_LINES, "1", -+ IFernflowerPreferences.USE_JAD_VARNAMING, "1" -+ ); -+ } -+ -+ @Test public void testClassFields() { doTest("pkg/TestJADNaming"); } -+ -+} -diff --git a/testData/classes/pkg/TestJADNaming.class b/testData/classes/pkg/TestJADNaming.class -new file mode 100644 -index 0000000000000000000000000000000000000000..ce5676d7c337af79875dd42852333b71b071644c -GIT binary patch -literal 379 -zcmY+8J5Iwu5QhJ?*Iqvo93vSCkrYq`3fv&mgh&XK0zoJe(XWkVIS(faHdo*n$rY$T -z6dZtxV{i(>*g;54F^~VB{dPXS-`)Y7pkYBpU0_SVVbD8imgZdswS9QUz%OR^F@tlR -zW^uomhVf!3!wD(8S7Z@GeUQs&d?V+TOb`ZZFe?^O+)K-~?P2_oU!7m}H8CzCH`$VilZF+Q0Tfc6ws&8DC;z}s4}YB(F@o!H4K8Xz7Z)K -zf2&XQ)FkiJRlho}_&js%*RJcV0>0N=!fbhb1(gSy8t6O_YG8Ppr!Qf7!ZXMz;YtPH -nAtb1C3Em`R8x{iC75o6onnX>&Vidp{yD)#JjY3D+6|43GV%Iy? - -literal 0 -HcmV?d00001 - -diff --git a/testData/results/TestJADNaming.dec b/testData/results/TestJADNaming.dec -new file mode 100644 -index 0000000000000000000000000000000000000000..b5d7ed54d77cc30c25688e1989a5a63eafaf863f ---- /dev/null -+++ b/testData/results/TestJADNaming.dec -@@ -0,0 +1,81 @@ -+package pkg; -+ -+public class TestJADNaming { -+ public void Func() { -+ short short1 = 1000;// 7 -+ short short2 = 2000; -+ short short3 = 3000; -+ short short4 = 4000; -+ if (short1 != short2 && short3 == short4) {// 8 -+ ; -+ } -+ -+ boolean flag = true;// 9 -+ boolean flag1 = false; -+ boolean flag2 = true; -+ boolean flag3 = false; -+ if (flag != flag1 && flag2 == flag3) {// 10 -+ ; -+ } -+ -+ }// 11 -+} -+ -+class 'pkg/TestJADNaming' { -+ method 'Func ()V' { -+ 0 4 -+ 1 4 -+ 2 4 -+ 3 4 -+ 4 5 -+ 5 5 -+ 6 5 -+ 7 5 -+ 8 6 -+ 9 6 -+ a 6 -+ b 6 -+ c 7 -+ d 7 -+ e 7 -+ f 7 -+ 10 7 -+ 11 8 -+ 12 8 -+ 13 8 -+ 16 8 -+ 17 8 -+ 18 8 -+ 19 8 -+ 1c 12 -+ 1d 12 -+ 1e 12 -+ 1f 13 -+ 20 13 -+ 21 13 -+ 22 14 -+ 23 14 -+ 24 14 -+ 25 15 -+ 26 15 -+ 27 15 -+ 28 16 -+ 29 16 -+ 2a 16 -+ 2b 16 -+ 2c 16 -+ 2f 16 -+ 30 16 -+ 31 16 -+ 32 16 -+ 33 16 -+ 36 20 -+ } -+} -+ -+Lines mapping: -+7 <-> 5 -+8 <-> 9 -+9 <-> 13 -+10 <-> 17 -+11 <-> 21 -diff --git a/testData/src/pkg/TestJADNaming.java b/testData/src/pkg/TestJADNaming.java -new file mode 100644 -index 0000000000000000000000000000000000000000..87e1c035ea3a6fd049bb95ba09935cc674afacd4 ---- /dev/null -+++ b/testData/src/pkg/TestJADNaming.java -@@ -0,0 +1,12 @@ -+package pkg; -+ -+import java.io.File; -+ -+public class TestJADNaming { -+ public void Func() { -+ int a = 1000, b = 2000, c = 3000, d = 4000; -+ if (a == b || c == d); -+ boolean flag1 = true, flag2 = false, flag3 = true, flag4 = false; -+ if (flag1 == flag2 || flag3 == flag4); -+ } -+} -\ No newline at end of file diff --git a/FernFlower-Patches/0012-Fix-primitive-un-boxing-issues.patch b/FernFlower-Patches/0012-Fix-primitive-un-boxing-issues.patch deleted file mode 100644 index 80cad44..0000000 --- a/FernFlower-Patches/0012-Fix-primitive-un-boxing-issues.patch +++ /dev/null @@ -1,1035 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Thu, 11 May 2017 03:24:33 -0700 -Subject: [PATCH] Fix primitive un/boxing issues. - - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -index e005b2941b4e76b736b8d00905726ac8500c3dc2..bc8c421206b44539c2f2da859658102f2b71af73 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java -@@ -1027,12 +1027,14 @@ public class ExprProcessor implements CodeConstants { - - if (unbox) { - // "unbox" invocation parameters, e.g. 'byteSet.add((byte)123)' or 'new ShortContainer((short)813)' -- if (exprent.type == Exprent.EXPRENT_INVOCATION && ((InvocationExprent)exprent).isBoxingCall()) { -- InvocationExprent invocationExprent = (InvocationExprent)exprent; -- exprent = invocationExprent.getParameters().get(0); -- int paramType = invocationExprent.getDescriptor().params[0].getType(); -- if (exprent.type == Exprent.EXPRENT_CONST && ((ConstExprent)exprent).getConstType().getType() != paramType) { -- leftType = new VarType(paramType); -+ if (exprent.type == Exprent.EXPRENT_INVOCATION) { -+ InvocationExprent invocationExprent = (InvocationExprent) exprent; -+ if (invocationExprent.isBoxingCall() && !invocationExprent.shouldForceBoxing()) { -+ exprent = invocationExprent.getParameters().get(0); -+ int paramType = invocationExprent.getDescriptor().params[0].getType(); -+ if (exprent.type == Exprent.EXPRENT_CONST && ((ConstExprent) exprent).getConstType().getType() != paramType) { -+ leftType = new VarType(paramType); -+ } - } - } - } -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index f18ef04b350a5f6d4599282aef5ea3f6e3dce778..ec2d6931c9426913680fd2ec180483389d96ac4b 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -@@ -533,6 +533,19 @@ public class FunctionExprent extends Exprent { - .append(")"); - default -> { - assert funcType <= FUNCTION_I2S; -+ // We can't directly cast some object types, so we need to make sure the unboxing happens. -+ // The types seem to be inconsistant but there is no harm in forcing the unboxing when not strictly needed. -+ // Type | Works | Doesn't -+ // Integer| LFD | BCS -+ // Long | FD | I -+ // Float | D | IL -+ // Double | | ILF -+ if (lstOperands.get(0).type == Exprent.EXPRENT_INVOCATION) { -+ InvocationExprent inv = (InvocationExprent)lstOperands.get(0); -+ if (inv.isUnboxingCall()) { -+ inv.forceUnboxing(true); -+ } -+ } - yield wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("(" + ExprProcessor.getTypeName( - TYPES[funcType - FUNCTION_I2L], Collections.emptyList()) + ")"); - } -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 2d8abaec74b301f76fcd4149600c1da72cc9b6c4..d51f0eba4a80cad4159a5135b2d87b8d405c0ed9 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -@@ -59,6 +59,8 @@ public class InvocationExprent extends Exprent { - private List parameters = new ArrayList<>(); - private List bootstrapArguments; - private List genericArgs = new ArrayList<>(); -+ private boolean forceBoxing = false; -+ private boolean forceUnboxing = false; - - public InvocationExprent() { - super(EXPRENT_INVOCATION); -@@ -256,10 +258,10 @@ public class InvocationExprent extends Exprent { - } - - if (isStatic) { -- if (isBoxingCall() && canIgnoreBoxing) { -+ if (isBoxingCall() && canIgnoreBoxing && !forceBoxing) { - // process general "boxing" calls, e.g. 'Object[] data = { true }' or 'Byte b = 123' - // here 'byte' and 'short' values do not need an explicit narrowing type cast -- ExprProcessor.getCastedExprent(parameters.get(0), descriptor.params[0], buf, indent, false, false, false, false, tracer); -+ ExprProcessor.getCastedExprent(parameters.get(0), descriptor.params[0], buf, indent, false, false, true, false, tracer); - return buf; - } - -@@ -305,16 +307,36 @@ public class InvocationExprent extends Exprent { - TextUtil.writeQualifiedSuper(buf, super_qualifier); - } - else if (instance != null) { -- TextBuffer res = instance.toJava(indent, tracer); -- -- if (isUnboxingCall()) { -+ VarType leftType = new VarType(CodeConstants.TYPE_OBJECT, 0, className); -+ if (isUnboxingCall() && !forceUnboxing) { - // we don't print the unboxing call - no need to bother with the instance wrapping / casting -- buf.append(res); -+ if (instance.type == Exprent.EXPRENT_FUNCTION) { -+ FunctionExprent func = (FunctionExprent)instance; -+ if (func.getFuncType() == FunctionExprent.FUNCTION_CAST && func.getLstOperands().get(1).type == Exprent.EXPRENT_CONST) { -+ ConstExprent _const = (ConstExprent)func.getLstOperands().get(1); -+ boolean skipCast = false; -+ -+ if (func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) { -+ VarType inferred = func.getLstOperands().get(0).getInferredExprType(leftType); -+ skipCast = inferred.getType() != CodeConstants.TYPE_OBJECT || -+ DecompilerContext.getStructContext().instanceOf(inferred.getValue(), this.className); -+ } else if (this.className.equals(_const.getConstType().getValue())) { -+ skipCast = true; -+ } -+ -+ if (skipCast) { -+ buf.append(func.getLstOperands().get(0).toJava(indent, tracer)); -+ return buf; -+ } -+ } -+ } -+ buf.append(instance.toJava(indent, tracer)); - return buf; - } - -+ TextBuffer res = instance.toJava(indent, tracer); -+ - VarType rightType = instance.getExprType(); -- VarType leftType = new VarType(CodeConstants.TYPE_OBJECT, 0, className); - - if (rightType.equals(VarType.VARTYPE_OBJECT) && !leftType.equals(rightType)) { - buf.append("((").append(ExprProcessor.getCastTypeName(leftType, Collections.emptyList())).append(")"); -@@ -410,9 +432,88 @@ public class InvocationExprent extends Exprent { - } - } - -- boolean firstParameter = true; - int start = isEnum ? 2 : 0; -+ List parameters = new ArrayList<>(this.parameters); -+ VarType[] types = Arrays.copyOf(descriptor.params, descriptor.params.length); - for (int i = start; i < parameters.size(); i++) { -+ Exprent par = parameters.get(i); -+ if (par.type == Exprent.EXPRENT_INVOCATION) { -+ InvocationExprent inv = (InvocationExprent)par; -+ // "unbox" invocation parameters, e.g. 'byteSet.add((byte)123)' or 'new ShortContainer((short)813)' -+ //However, we must make sure we don't accidentally make the call ambiguous. -+ //An example being List, remove(Integer.valueOf(1)) and remove(1) are different functions -+ if (inv.isBoxingCall()) { -+ Exprent value = inv.parameters.get(0); -+ types[i] = value.getExprType(); //Infer? -+ //Unboxing in this case is lossy, so we need to explicitly set the type -+ if (types[i].getTypeFamily() == CodeConstants.TYPE_FAMILY_INTEGER) { -+ types[i] = -+ "java/lang/Short".equals(inv.className) ? VarType.VARTYPE_SHORT : -+ "java/lang/Byte".equals(inv.className) ? VarType.VARTYPE_BYTE : -+ "java/lang/Integer".equals(inv.className) ? VarType.VARTYPE_INT : -+ VarType.VARTYPE_CHAR; -+ } -+ -+ int count = 0; -+ StructClass stClass = DecompilerContext.getStructContext().getClass(className); -+ if (stClass != null) { -+ nextMethod: -+ for (StructMethod mt : stClass.getMethods()) { -+ if (name.equals(mt.getName())) { -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); -+ if (md.params.length == descriptor.params.length) { -+ for (int x = 0; x < md.params.length; x++) { -+ if (md.params[x].getTypeFamily() != descriptor.params[x].getTypeFamily() && -+ md.params[x].getTypeFamily() != types[x].getTypeFamily()) { -+ continue nextMethod; -+ } -+ } -+ count++; -+ } -+ } -+ } -+ } -+ -+ if (count != matches.size()) { //We become more ambiguous? Lets keep the explicit boxing -+ types[i] = descriptor.params[i]; -+ inv.forceBoxing = true; -+ } else { -+ value.addBytecodeOffsets(inv.bytecode); //Keep the bytecode for matching/debug -+ parameters.set(i, value); -+ } -+ } -+ // We also need to care about when things are intentionally unboxed to call a different overloaded method, -+ //and skipping unboxing causes us to call ourselves. -+ // EXA: -+ // int compare(Integer a, Integer b) { return this.compare(a.intValue(), b.intValue()); } -+ // int compare(int a, int b) { return a - b; } -+ // Allowing the first function to unbox would cause infinite recursion -+ // Right now it just do a quick check, but a proper check would be to do compiler like inference of argument -+ // types, and check unboxing as needed. Currently it causes some false forces -+ else if (inv.isUnboxingCall() && !inv.shouldForceUnboxing()) { -+ StructClass stClass = DecompilerContext.getStructContext().getClass(className); -+ if (stClass != null) { -+ for (StructMethod mt : stClass.getMethods()) { -+ if (name.equals(mt.getName()) && !stringDescriptor.equals(mt.getDescriptor())) { -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); -+ if (md.params.length == descriptor.params.length) { -+ if (md.params[i].getType() == CodeConstants.TYPE_OBJECT) { -+ if (DecompilerContext.getStructContext().instanceOf(inv.getInstance().getExprType().getValue(), md.params[i].getValue())) { -+ inv.forceUnboxing(true); -+ break; -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ -+ boolean firstParameter = true; -+ for (int i = start; i < this.parameters.size(); i++) { - if (mask == null || mask.get(i) == null) { - TextBuffer buff = new TextBuffer(); - boolean ambiguous = setAmbiguousParameters.get(i); -@@ -446,7 +547,7 @@ public class InvocationExprent extends Exprent { - */ - - // 'byte' and 'short' literals need an explicit narrowing type cast when used as a parameter -- ExprProcessor.getCastedExprent(parameters.get(i), descriptor.params[i], buff, indent, true, ambiguous, true, true, tracer); -+ ExprProcessor.getCastedExprent(this.parameters.get(i), types[i], buff, indent, true, ambiguous, true, true, tracer); - - // the last "new Object[0]" in the vararg call is not printed - if (buff.length() > 0) { -@@ -499,7 +600,7 @@ public class InvocationExprent extends Exprent { - } - - if (paramType == CodeConstants.TYPE_BYTECHAR || paramType == CodeConstants.TYPE_SHORTCHAR) { -- if (className.equals("java/lang/Character")) { -+ if (className.equals("java/lang/Character") || className.equals("java/lang/Short")) { - return true; - } - } -@@ -550,6 +651,18 @@ public class InvocationExprent extends Exprent { - return !isStatic && parameters.size() == 0 && className.equals(UNBOXING_METHODS.get(name)); - } - -+ public boolean shouldForceBoxing() { -+ return forceBoxing; -+ } -+ -+ public void forceUnboxing(boolean value) { -+ this.forceUnboxing = value; -+ } -+ -+ public boolean shouldForceUnboxing() { -+ return this.forceUnboxing; -+ } -+ - private List getMatchedDescriptors() { - List matches = new ArrayList<>(); - StructClass cl = DecompilerContext.getStructContext().getClass(className); -@@ -579,6 +692,8 @@ public class InvocationExprent extends Exprent { - return EMPTY_BIT_SET; - } - -+ BitSet missed = new BitSet(parameters.size()); -+ - // check if a call is unambiguous - StructMethod mt = cl.getMethod(InterpreterUtil.makeUniqueKey(name, stringDescriptor)); - if (mt != null) { -@@ -588,18 +703,50 @@ public class InvocationExprent extends Exprent { - for (int i = 0; i < md.params.length; i++) { - if (!md.params[i].equals(parameters.get(i).getExprType())) { - exact = false; -- break; -+ missed.set(i); - } - } - if (exact) return EMPTY_BIT_SET; - } - } - -+ List mtds = new ArrayList<>(); -+ for (StructMethod mtt : matches) { -+ boolean failed = false; -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mtt.getDescriptor()); -+ for (int i = 0; i < parameters.size(); i++) { -+ VarType ptype = parameters.get(i).getExprType(); -+ if (!missed.get(i)) { -+ if (!md.params[i].equals(ptype)) { -+ failed = true; -+ break; -+ } -+ } -+ else { -+ if (md.params[i].getType() == CodeConstants.TYPE_OBJECT) { -+ if (ptype.getType() != CodeConstants.TYPE_NULL) { -+ if (!DecompilerContext.getStructContext().instanceOf(ptype.getValue(), md.params[i].getValue())) { -+ failed = true; -+ break; -+ } -+ } -+ } -+ } -+ } -+ if (!failed) { -+ mtds.add(mtt); -+ } -+ } -+ //TODO: This still causes issues in the case of: -+ //add(Object) -+ //add(Object...) -+ //Try and detect varargs/array? -+ - // mark parameters - BitSet ambiguous = new BitSet(descriptor.params.length); - for (int i = 0; i < descriptor.params.length; i++) { - VarType paramType = descriptor.params[i]; -- for (StructMethod mtt : matches) { -+ for (StructMethod mtt : mtds) { - - GenericMethodDescriptor gen = mtt.getSignature(); //TODO: Find synthetic flags for params, as Enum generic signatures do no contain the String,int params - if (gen != null && gen.parameterTypes.size() > i && gen.parameterTypes.get(i).isGeneric()) { -diff --git a/testData/results/TestPrimitives.dec b/testData/results/TestPrimitives.dec -index dcbf031b69cc65b108a2cba8f894d02027372032..0f74573b4b8df58023a80b059dcf6930fd08fabf 100644 ---- a/testData/results/TestPrimitives.dec -+++ b/testData/results/TestPrimitives.dec -@@ -3,6 +3,26 @@ package pkg; - import java.util.HashMap; - - public class TestPrimitives { -+ private void testInvalidUnboxing() { -+ List lst = null;// 7 -+ lst.remove(Integer.valueOf(0));// 8 -+ this.genericBoxing((short)0);// 9 -+ int a = this.genericReturn(lst);// 10 -+ List b = null;// 11 -+ this.genericParameter(b, (byte)0);// 12 -+ this.genericParameter(lst, 0);// 13 -+ }// 14 -+ -+ private void genericBoxing(T value) { -+ }// 16 -+ -+ private T genericReturn(List value) { -+ return value.get(0);// 17 -+ } -+ -+ private void genericParameter(List p, T v) { -+ }// 18 -+ - public void printAll() { - this.printBoolean(true);// 8 - this.printByte((byte)123);// 9 -@@ -171,179 +191,498 @@ public class TestPrimitives { - } - - class 'pkg/TestPrimitives' { -- method 'printAll ()V' { -- 0 4 -- 1 4 -- 2 4 -- 3 4 -- 4 4 -- 5 5 -- 6 5 -- 7 5 -- 8 5 -- 9 5 -- a 5 -- b 6 -- c 6 -- d 6 -- e 6 -- f 6 -- 10 6 -- 11 6 -- 12 7 -- 13 7 -- 14 7 -- 15 7 -- 16 7 -- 17 7 -- 18 8 -- 19 8 -- 1a 8 -- 1b 8 -- 1c 8 -- 1d 8 -- 1e 8 -+ method 'testInvalidUnboxing ()V' { -+ 0 6 -+ 1 6 -+ 2 7 -+ 3 7 -+ 4 7 -+ 5 7 -+ 6 7 -+ 7 7 -+ 8 7 -+ 9 7 -+ a 7 -+ b 7 -+ d 8 -+ e 8 -+ f 8 -+ 10 8 -+ 11 8 -+ 12 8 -+ 13 8 -+ 14 8 -+ 15 9 -+ 16 9 -+ 17 9 -+ 18 9 -+ 19 9 -+ 1d 9 -+ 1e 9 - 1f 9 - 20 9 -- 21 9 -- 22 9 -- 23 9 -- 24 9 -- 25 10 -- 26 10 -- 27 10 -- 28 10 -- 29 10 -- 2a 10 -- 2b 10 -- 2c 11 -- 2d 11 -- 2e 11 -- 2f 11 -- 30 11 -- 31 11 -+ 21 10 -+ 22 10 -+ 23 11 -+ 24 11 -+ 25 11 -+ 26 11 -+ 27 11 -+ 28 11 -+ 29 11 -+ 2a 11 -+ 2b 11 -+ 2c 12 -+ 2d 12 -+ 2e 12 -+ 2f 12 -+ 30 12 -+ 31 12 - 32 12 - 33 12 -- 37 12 -- 3b 13 -- 40 13 -- 44 14 -- 4a 14 -- 4e 15 -- 52 15 -- 56 16 -- 5b 16 -- 5f 17 -- 65 17 -- 69 18 -- 6e 18 -- 72 19 -- 78 19 -- 7c 20 -- 81 20 -- 85 21 -- 87 21 -- 8a 21 -- 8d 21 -- 91 22 -- 93 22 -- 96 22 -- 99 22 -- 9d 23 -- 9f 23 -- a2 23 -- a5 23 -- a9 24 -- ab 24 -- ae 24 -- b1 24 -- b5 25 -- b7 25 -- ba 25 -- bd 25 -- c1 26 -- c3 26 -- c6 26 -- c9 26 -- cd 27 -- cf 27 -- d2 27 -- d5 27 -- dd 28 -- e2 28 -- e5 28 -- ea 29 -- ed 29 -- f0 29 -- f5 30 -- f8 30 -- fb 30 -- fe 31 -- 101 31 -- 10a 31 -- 10b 31 -- 111 31 -- 112 31 -- 118 31 -- 11b 31 -- 121 31 -- 123 31 -- 129 31 -- 12b 31 -- 131 31 -- 134 31 -- 138 31 -- 13c 32 -- 13f 32 -- 148 32 -- 14b 32 -- 152 32 -- 155 32 -- 15c 32 -- 15f 32 -- 166 32 -- 169 32 -- 16d 32 -- 175 33 -- 176 33 -- 178 33 -- 17b 33 -- 17d 33 -- 180 33 -- 182 33 -- 185 33 -- 18f 34 -- 194 34 -- 19a 34 -- 19f 34 -- 1a5 34 -- 1aa 34 -- 1b0 34 -- 1b5 34 -- 1c1 35 -- 1c3 35 -- 1c6 35 -- 1c9 35 -- 1cb 35 -- 1ce 35 -- 1d1 35 -- 1d3 35 -- 1d6 35 -- 1d9 35 -- 1db 35 -- 1de 35 -- 1e1 35 -- 1e3 35 -- 1e6 35 -- 1e9 35 -- 1eb 35 -- 1ee 35 -- 1f1 35 -- 1f3 35 -- 1f6 35 -- 1fd 35 -- 202 35 -- 209 36 -+ 34 12 -+ 35 13 -+ } -+ -+ method 'genericBoxing (Ljava/lang/Object;)V' { -+ 0 16 -+ } -+ -+ method 'genericReturn (Ljava/util/List;)Ljava/lang/Object;' { -+ 0 19 -+ 1 19 -+ 2 19 -+ 3 19 -+ 4 19 -+ 5 19 -+ 6 19 -+ 7 19 -+ } -+ -+ method 'genericParameter (Ljava/util/List;Ljava/lang/Object;)V' { -+ 0 23 -+ } -+ -+ method 'printAll ()V' { -+ 0 26 -+ 1 26 -+ 2 26 -+ 3 26 -+ 4 26 -+ 5 27 -+ 6 27 -+ 7 27 -+ 8 27 -+ 9 27 -+ a 27 -+ b 28 -+ c 28 -+ d 28 -+ e 28 -+ f 28 -+ 10 28 -+ 11 28 -+ 12 29 -+ 13 29 -+ 14 29 -+ 15 29 -+ 16 29 -+ 17 29 -+ 18 30 -+ 19 30 -+ 1a 30 -+ 1b 30 -+ 1c 30 -+ 1d 30 -+ 1e 30 -+ 1f 31 -+ 20 31 -+ 21 31 -+ 22 31 -+ 23 31 -+ 24 31 -+ 25 32 -+ 26 32 -+ 27 32 -+ 28 32 -+ 29 32 -+ 2a 32 -+ 2b 32 -+ 2c 33 -+ 2d 33 -+ 2e 33 -+ 2f 33 -+ 30 33 -+ 31 33 -+ 32 34 -+ 33 34 -+ 34 34 -+ 35 34 -+ 36 34 -+ 37 34 -+ 38 34 -+ 39 34 -+ 3a 35 -+ 3b 35 -+ 3c 35 -+ 3d 35 -+ 3e 35 -+ 3f 35 -+ 40 35 -+ 41 35 -+ 42 35 -+ 43 36 -+ 44 36 -+ 45 36 -+ 46 36 -+ 47 36 -+ 48 36 -+ 49 36 -+ 4a 36 -+ 4b 36 -+ 4c 36 -+ 4d 37 -+ 4e 37 -+ 4f 37 -+ 50 37 -+ 51 37 -+ 52 37 -+ 53 37 -+ 54 37 -+ 55 38 -+ 56 38 -+ 57 38 -+ 58 38 -+ 59 38 -+ 5a 38 -+ 5b 38 -+ 5c 38 -+ 5d 38 -+ 5e 39 -+ 5f 39 -+ 60 39 -+ 61 39 -+ 62 39 -+ 63 39 -+ 64 39 -+ 65 39 -+ 66 39 -+ 67 39 -+ 68 40 -+ 69 40 -+ 6a 40 -+ 6b 40 -+ 6c 40 -+ 6d 40 -+ 6e 40 -+ 6f 40 -+ 70 40 -+ 71 41 -+ 72 41 -+ 73 41 -+ 74 41 -+ 75 41 -+ 76 41 -+ 77 41 -+ 78 41 -+ 79 41 -+ 7a 41 -+ 7b 42 -+ 7c 42 -+ 7d 42 -+ 7e 42 -+ 7f 42 -+ 80 42 -+ 81 42 -+ 82 42 -+ 83 42 -+ 84 43 -+ 85 43 -+ 86 43 -+ 87 43 -+ 88 43 -+ 89 43 -+ 8a 43 -+ 8b 43 -+ 8c 43 -+ 8d 43 -+ 8e 43 -+ 8f 43 -+ 90 44 -+ 91 44 -+ 92 44 -+ 93 44 -+ 94 44 -+ 95 44 -+ 96 44 -+ 97 44 -+ 98 44 -+ 99 44 -+ 9a 44 -+ 9b 44 -+ 9c 45 -+ 9d 45 -+ 9e 45 -+ 9f 45 -+ a0 45 -+ a1 45 -+ a2 45 -+ a3 45 -+ a4 45 -+ a5 45 -+ a6 45 -+ a7 45 -+ a8 46 -+ a9 46 -+ aa 46 -+ ab 46 -+ ac 46 -+ ad 46 -+ ae 46 -+ af 46 -+ b0 46 -+ b1 46 -+ b2 46 -+ b3 46 -+ b4 47 -+ b5 47 -+ b6 47 -+ b7 47 -+ b8 47 -+ b9 47 -+ ba 47 -+ bb 47 -+ bc 47 -+ bd 47 -+ be 47 -+ bf 47 -+ c0 48 -+ c1 48 -+ c2 48 -+ c3 48 -+ c4 48 -+ c5 48 -+ c6 48 -+ c7 48 -+ c8 48 -+ c9 48 -+ ca 48 -+ cb 48 -+ cc 49 -+ cd 49 -+ ce 49 -+ cf 49 -+ d0 49 -+ d1 49 -+ d2 49 -+ d3 49 -+ d4 49 -+ d5 49 -+ d6 49 -+ d7 49 -+ d8 50 -+ dd 50 -+ de 50 -+ e2 50 -+ e3 50 -+ e4 50 -+ e5 50 -+ e6 50 -+ e7 50 -+ e8 51 -+ e9 51 -+ ea 51 -+ eb 51 -+ ec 51 -+ ed 51 -+ ee 51 -+ ef 51 -+ f0 51 -+ f1 51 -+ f2 51 -+ f3 52 -+ f4 52 -+ f5 52 -+ f6 52 -+ f7 52 -+ f8 52 -+ f9 52 -+ fa 52 -+ fb 52 -+ fc 52 -+ fd 52 -+ fe 53 -+ ff 53 -+ 100 53 -+ 101 53 -+ 102 53 -+ 10a 53 -+ 10b 53 -+ 10c 53 -+ 10d 53 -+ 111 53 -+ 112 53 -+ 113 53 -+ 114 53 -+ 118 53 -+ 119 53 -+ 11a 53 -+ 11b 53 -+ 11c 53 -+ 11d 53 -+ 121 53 -+ 122 53 -+ 123 53 -+ 124 53 -+ 125 53 -+ 129 53 -+ 12a 53 -+ 12b 53 -+ 12c 53 -+ 12d 53 -+ 131 53 -+ 132 53 -+ 133 53 -+ 134 53 -+ 135 53 -+ 136 53 -+ 138 53 -+ 139 53 -+ 13a 53 -+ 13c 54 -+ 13d 54 -+ 13e 54 -+ 13f 54 -+ 140 54 -+ 147 54 -+ 148 54 -+ 149 54 -+ 14a 54 -+ 14b 54 -+ 14c 54 -+ 14d 54 -+ 151 54 -+ 152 54 -+ 153 54 -+ 154 54 -+ 155 54 -+ 156 54 -+ 157 54 -+ 15b 54 -+ 15c 54 -+ 15d 54 -+ 15e 54 -+ 15f 54 -+ 160 54 -+ 161 54 -+ 165 54 -+ 166 54 -+ 167 54 -+ 168 54 -+ 169 54 -+ 16a 54 -+ 16b 54 -+ 16d 54 -+ 16e 54 -+ 16f 54 -+ 175 55 -+ 176 55 -+ 177 55 -+ 178 55 -+ 179 55 -+ 17a 55 -+ 17b 55 -+ 17c 55 -+ 17d 55 -+ 17e 55 -+ 17f 55 -+ 180 55 -+ 181 55 -+ 182 55 -+ 183 55 -+ 184 55 -+ 185 55 -+ 186 55 -+ 18f 56 -+ 190 56 -+ 194 56 -+ 195 56 -+ 196 56 -+ 19a 56 -+ 19b 56 -+ 19f 56 -+ 1a0 56 -+ 1a1 56 -+ 1a5 56 -+ 1a6 56 -+ 1aa 56 -+ 1ab 56 -+ 1ac 56 -+ 1b0 56 -+ 1b1 56 -+ 1b5 56 -+ 1c1 57 -+ 1c2 57 -+ 1c3 57 -+ 1c4 57 -+ 1c5 57 -+ 1c6 57 -+ 1c7 57 -+ 1c8 57 -+ 1c9 57 -+ 1ca 57 -+ 1cb 57 -+ 1cc 57 -+ 1cd 57 -+ 1ce 57 -+ 1cf 57 -+ 1d0 57 -+ 1d1 57 -+ 1d2 57 -+ 1d3 57 -+ 1d4 57 -+ 1d5 57 -+ 1d6 57 -+ 1d7 57 -+ 1d8 57 -+ 1d9 57 -+ 1da 57 -+ 1db 57 -+ 1dc 57 -+ 1dd 57 -+ 1de 57 -+ 1df 57 -+ 1e0 57 -+ 1e1 57 -+ 1e2 57 -+ 1e3 57 -+ 1e4 57 -+ 1e5 57 -+ 1e6 57 -+ 1e7 57 -+ 1e8 57 -+ 1e9 57 -+ 1ea 57 -+ 1eb 57 -+ 1ec 57 -+ 1ed 57 -+ 1ee 57 -+ 1ef 57 -+ 1f0 57 -+ 1f1 57 -+ 1f2 57 -+ 1f3 57 -+ 1f4 57 -+ 1f5 57 -+ 1f6 57 -+ 1f7 57 -+ 1f8 57 -+ 1fd 57 -+ 1fe 57 -+ 202 57 -+ 203 57 -+ 204 57 -+ 209 58 - } - - method ' (ZBSIJFDC)V' { -diff --git a/testData/src/pkg/TestPrimitives.java b/testData/src/pkg/TestPrimitives.java -index 36302524a2ecfae64e25098eff1318b8b7d11d51..acfe886bf4578fe0cd0b1a58bf4073eb97436025 100644 ---- a/testData/src/pkg/TestPrimitives.java -+++ b/testData/src/pkg/TestPrimitives.java -@@ -3,6 +3,19 @@ package pkg; - import java.util.*; - - public class TestPrimitives { -+ private void testInvalidUnboxing() { -+ List lst = null; -+ lst.remove(Integer.valueOf(0)); -+ this.genericBoxing((short)0); -+ int a = genericReturn(lst); -+ List b = null; -+ this.genericParameter(b, (byte)0); -+ this.genericParameter(lst, 0); -+ } -+ -+ private void genericBoxing(T value) {} -+ private T genericReturn(List value) { return value.get(0); } -+ private void genericParameter(List p, T v) {} - - public void printAll() { - printBoolean(true); diff --git a/FernFlower-Patches/0012-Some-synthetic-anon-classes-are-being-detected-as-me.patch b/FernFlower-Patches/0012-Some-synthetic-anon-classes-are-being-detected-as-me.patch new file mode 100644 index 0000000..def67bb --- /dev/null +++ b/FernFlower-Patches/0012-Some-synthetic-anon-classes-are-being-detected-as-me.patch @@ -0,0 +1,26 @@ +From 4e2882cb40ea460cb1f4a22c85a017cd853b308c Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sun, 2 Aug 2015 21:14:56 -0700 +Subject: [PATCH 012/122] Some synthetic anon classes are being detected as + member classes. Unknown why, however this fixes the consturctor argument. + +--- + .../java/decompiler/modules/decompiler/exps/NewExprent.java | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +index 6dad7c9..0297a55 100644 +--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java ++++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +@@ -327,7 +327,7 @@ public class NewExprent extends Exprent { + + if (i == lstParameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL) { + ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(leftType.value); +- if (node != null && node.type == ClassNode.CLASS_ANONYMOUS) { ++ if (node != null && (node.namelessConstructorStub || node.type == ClassNode.CLASS_ANONYMOUS)) { + break; // skip last parameter of synthetic constructor call + } + } +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0013-Add-Minecraft-test-framework.patch b/FernFlower-Patches/0013-Add-Minecraft-test-framework.patch deleted file mode 100644 index 1b26401..0000000 --- a/FernFlower-Patches/0013-Add-Minecraft-test-framework.patch +++ /dev/null @@ -1,148 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Wed, 19 Apr 2017 01:59:28 -0700 -Subject: [PATCH] Add Minecraft test framework - - -diff --git a/test/org/jetbrains/java/decompiler/MinecraftTest.java b/test/org/jetbrains/java/decompiler/MinecraftTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1f9a9dd03dab30cdb464bfc4901b9c592d558b8f ---- /dev/null -+++ b/test/org/jetbrains/java/decompiler/MinecraftTest.java -@@ -0,0 +1,136 @@ -+package org.jetbrains.java.decompiler; -+ -+import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -+ -+import java.io.File; -+import java.io.IOException; -+import java.nio.file.Files; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+import java.util.Map.Entry; -+ -+import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler; -+import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger; -+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; -+import org.junit.Test; -+ -+import com.google.gson.Gson; -+import com.google.gson.GsonBuilder; -+ -+public class MinecraftTest extends SingleClassesTestBase { -+ private static final String MC_PATH = "Z:\\Projects\\MCP\\BlueMining\\mcp_update\\new"; -+ private static final Map RESULTS = new HashMap<>(); -+ private static final Gson GSON = new GsonBuilder().create(); -+ -+ @Override -+ protected Map getDecompilerOptions() { -+ return Map.of( -+ IFernflowerPreferences.DECOMPILE_INNER,"1", -+ IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES,"1", -+ IFernflowerPreferences.ASCII_STRING_CHARACTERS,"1", -+ IFernflowerPreferences.LOG_LEVEL, "TRACE", -+ IFernflowerPreferences.REMOVE_SYNTHETIC, "1", -+ IFernflowerPreferences.REMOVE_BRIDGE, "1", -+ IFernflowerPreferences.USE_DEBUG_VAR_NAMES, "1", -+ IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "1" -+ ); -+ } -+ -+ @Override -+ public void setUp() throws IOException { -+ fixture = new DecompilerTestFixture() { -+ private ConsoleDecompiler decompiler; -+ -+ @Override -+ public void setUp(Map customOptions) throws IOException { -+ File tempDir = File.createTempFile("decompiler_test_", "_dir"); -+ assertThat(tempDir.delete()).isTrue(); -+ -+ File targetDir = new File(tempDir, "decompiled"); -+ assertThat(targetDir.mkdirs()).isTrue(); -+ -+ Map options = new HashMap<>(); -+ options.put(IFernflowerPreferences.LOG_LEVEL, "warn"); -+ options.put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1"); -+ options.put(IFernflowerPreferences.REMOVE_SYNTHETIC, "1"); -+ options.put(IFernflowerPreferences.REMOVE_BRIDGE, "1"); -+ options.put(IFernflowerPreferences.LITERALS_AS_IS, "1"); -+ options.put(IFernflowerPreferences.UNIT_TEST_MODE, "1"); -+ options.putAll(customOptions); -+ decompiler = new ConsoleDecompiler(targetDir, options, new PrintStreamLogger(System.out)) { -+ @Override -+ public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) { -+ RESULTS.put(path, content); -+ } -+ -+ @Override -+ public void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName, String content) { -+ RESULTS.put(qualifiedName, content); -+ } -+ }; -+ } -+ -+ @Override -+ public ConsoleDecompiler getDecompiler() { -+ return decompiler; -+ } -+ }; -+ fixture.setUp(getDecompilerOptions()); -+ fixture.setCleanup(false); -+ } -+ -+ @Override -+ protected void doTest(String testFile, String... companionFiles) { -+ File MC_JAR = new File(MC_PATH); -+ if (!MC_JAR.exists()) { -+ return; -+ } -+ -+ RESULTS.clear(); -+ -+ ConsoleDecompiler decompiler = fixture.getDecompiler(); -+ if (MC_JAR.isDirectory()) { -+ //decompiler.addSpace(new File(MC_JAR, "jars\\libraries"), false); -+ gatherLibraries(decompiler); -+ decompiler.addSource(new File(MC_JAR, "temp\\minecraft_ff_in.jar")); -+ } -+ else { -+ decompiler.addSource(MC_JAR); -+ } -+ decompiler.decompileContext(); -+ -+ for (Entry entry : RESULTS.entrySet()) { -+ if (!entry.getKey().startsWith(testFile)) { -+ continue; -+ } -+ System.out.println(entry.getKey()); -+ System.out.println(entry.getValue()); -+ } -+ } -+ -+ @SuppressWarnings("unchecked") -+ private void gatherLibraries(ConsoleDecompiler decompiler) { -+ try { -+ String version = null; -+ for (String line : Files.readAllLines(new File(MC_PATH, "conf/version.cfg").toPath())) { -+ if (line.startsWith("ClientVersion")) { -+ version = line.split(" ")[2]; -+ } -+ } -+ String data = new String(Files.readAllBytes(new File(MC_PATH, "jars/versions/" + version + "/" + version + ".json").toPath())); -+ List> libs = (List>)GSON.fromJson(data, Map.class).get("libraries"); -+ -+ for (Map e : libs) { -+ String path = ((Map>)e.get("downloads")).get("artifact").get("path"); -+ File lib = new File(MC_PATH, "jars/libraries/" + path); -+ decompiler.addLibrary(lib); -+ } -+ } catch (Exception e) { -+ throw new RuntimeException(e); -+ } -+ } -+ -+ @Test public void testWoodlandMansionPieces() { doTest("net/minecraft/world/gen/structure/WoodlandMansionPieces"); } -+ @Test public void testEntityPlayer() { doTest("net/minecraft/command/impl/SeedCommand"); } -+} diff --git a/FernFlower-Patches/0013-Fixed-last-test-all-tests-pass.patch b/FernFlower-Patches/0013-Fixed-last-test-all-tests-pass.patch new file mode 100644 index 0000000..bde73fa --- /dev/null +++ b/FernFlower-Patches/0013-Fixed-last-test-all-tests-pass.patch @@ -0,0 +1,74 @@ +From 089ba9f7ecc59787de6f28b51cbfc8ee077caf6c Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Sun, 2 Aug 2015 21:20:47 -0700 +Subject: [PATCH 013/122] Fixed last test, all tests pass. + +--- + .../TestClassSimpleBytecodeMapping.dec | 24 +++++++++---------- + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/testData/results/TestClassSimpleBytecodeMapping.dec b/testData/results/TestClassSimpleBytecodeMapping.dec +index a48375a..1a2532f 100644 +--- a/testData/results/TestClassSimpleBytecodeMapping.dec ++++ b/testData/results/TestClassSimpleBytecodeMapping.dec +@@ -33,17 +33,17 @@ public class TestClassSimpleBytecodeMapping { + var1.run();// 49 + }// 50 + +- public class InnerClass2 { +- public void print() { +- System.out.println("Inner2");// 54 +- }// 55 +- } +- + public class InnerClass { + public void print() { + System.out.println("Inner");// 44 + }// 45 + } ++ ++ public class InnerClass2 { ++ public void print() { ++ System.out.println("Inner2");// 54 ++ }// 55 ++ } + } + + class 'pkg/TestClassSimpleBytecodeMapping$1' { +@@ -96,7 +96,7 @@ class 'pkg/TestClassSimpleBytecodeMapping' { + } + } + +-class 'pkg/TestClassSimpleBytecodeMapping$InnerClass2' { ++class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' { + method 'print ()V' { + 0 37 + 3 37 +@@ -105,7 +105,7 @@ class 'pkg/TestClassSimpleBytecodeMapping$InnerClass2' { + } + } + +-class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' { ++class 'pkg/TestClassSimpleBytecodeMapping$InnerClass2' { + method 'print ()V' { + 0 43 + 3 43 +@@ -130,11 +130,11 @@ Lines mapping: + 36 <-> 25 + 38 <-> 27 + 40 <-> 30 +-44 <-> 44 +-45 <-> 45 ++44 <-> 38 ++45 <-> 39 + 49 <-> 33 + 50 <-> 34 +-54 <-> 38 +-55 <-> 39 ++54 <-> 44 ++55 <-> 45 + Not mapped: + 39 +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0014-Fix-how-class-types-are-determined-was-detecting-ano.patch b/FernFlower-Patches/0014-Fix-how-class-types-are-determined-was-detecting-ano.patch new file mode 100644 index 0000000..eb7efd6 --- /dev/null +++ b/FernFlower-Patches/0014-Fix-how-class-types-are-determined-was-detecting-ano.patch @@ -0,0 +1,197 @@ +From eeabc2fd9d388a3361b0ec89733add20e4ade8a6 Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Mon, 3 Aug 2015 15:07:46 -0700 +Subject: [PATCH 014/122] Fix how class types are determined, was detecting + anon classes as member classes. + +--- + .../decompiler/main/ClassesProcessor.java | 48 ++++++++++---- + .../attr/StructInnerClassesAttribute.java | 62 +++++++++++-------- + 2 files changed, 70 insertions(+), 40 deletions(-) + +diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +index b3e9d81..7f75a0c 100644 +--- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java ++++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +@@ -31,7 +31,10 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; + import org.jetbrains.java.decompiler.struct.StructClass; + import org.jetbrains.java.decompiler.struct.StructContext; + import org.jetbrains.java.decompiler.struct.StructMethod; ++import org.jetbrains.java.decompiler.struct.attr.StructEnclosingMethodAttribute; ++import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; + import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute; ++import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute.InnerClassInfo; + import org.jetbrains.java.decompiler.struct.gen.VarType; + import org.jetbrains.java.decompiler.util.InterpreterUtil; + +@@ -62,18 +65,37 @@ public class ClassesProcessor { + StructInnerClassesAttribute inner = (StructInnerClassesAttribute)cl.getAttributes().getWithKey("InnerClasses"); + if (inner != null) { + +- for (int i = 0; i < inner.getClassEntries().size(); i++) { +- +- int[] entry = inner.getClassEntries().get(i); +- String[] strEntry = inner.getStringEntries().get(i); ++ for (InnerClassInfo entry : inner.getEntries()) { + Object[] arr = new Object[4]; // arr[0] not used +- String innerName = strEntry[0]; ++ String innerName = entry.inner_class; + + // nested class type +- arr[2] = entry[1] == 0 ? (entry[2] == 0 ? ClassNode.CLASS_ANONYMOUS : ClassNode.CLASS_LOCAL) : ClassNode.CLASS_MEMBER; ++ if (entry.inner_class != null) { ++ if (entry.inner_name == null) { ++ arr[2] = ClassNode.CLASS_ANONYMOUS; ++ } ++ else { ++ StructClass in = context.getClass(entry.inner_class); ++ if (in == null) { // A referenced library that was not added to the context, make assumptions ++ arr[2] = ClassNode.CLASS_MEMBER; ++ } ++ else { ++ StructEnclosingMethodAttribute attr = (StructEnclosingMethodAttribute)in.getAttributes().getWithKey("EnclosingMethod"); ++ if (attr != null && attr.getMethodName() != null) { ++ arr[2] = ClassNode.CLASS_LOCAL; ++ } ++ else { ++ arr[2] = ClassNode.CLASS_MEMBER; ++ } ++ } ++ } ++ } ++ else { // This should never happen as inner_class and outer_class are NOT optional, make assumptions ++ arr[2] = ClassNode.CLASS_MEMBER; ++ } + + // original simple name +- String simpleName = strEntry[2]; ++ String simpleName = entry.inner_name; + String savedName = mapNewSimpleNames.get(innerName); + + if (savedName != null) { +@@ -90,12 +112,12 @@ public class ClassesProcessor { + arr[1] = simpleName; + + // original access flags +- arr[3] = entry[3]; ++ arr[3] = entry.access; + + // enclosing class + String enclClassName; +- if (entry[1] != 0) { +- enclClassName = strEntry[1]; ++ if (entry.outer_class != null) { ++ enclClassName = entry.outer_class; + } + else { + enclClassName = cl.qualifiedName; +@@ -163,13 +185,13 @@ public class ClassesProcessor { + StructClass scl = superNode.classStruct; + StructInnerClassesAttribute inner = (StructInnerClassesAttribute)scl.getAttributes().getWithKey("InnerClasses"); + +- if (inner == null || inner.getStringEntries().isEmpty()) { ++ if (inner == null || inner.getEntries().isEmpty()) { + DecompilerContext.getLogger().writeMessage(superClass + " does not contain inner classes!", IFernflowerLogger.Severity.WARN); + continue; + } + +- for (int i = 0; i < inner.getStringEntries().size(); i++) { +- String nestedClass = inner.getStringEntries().get(i)[0]; ++ for (InnerClassInfo info : inner.getEntries()) { ++ String nestedClass = info.inner_class; + if (!setNestedClasses.contains(nestedClass)) { + continue; + } +diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java +index 5969487..ecef558 100644 +--- a/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java ++++ b/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java +@@ -23,10 +23,21 @@ import java.util.ArrayList; + import java.util.Collections; + import java.util.List; + +-public class StructInnerClassesAttribute extends StructGeneralAttribute { ++/* ++ * InnerClasses_attribute { ++ * u2 attribute_name_index; ++ * u4 attribute_length; ++ * u2 number_of_classes; ++ * { u2 inner_class_info_index; ++ * u2 outer_class_info_index; ++ * u2 inner_name_index; ++ * u2 inner_class_access_flags; ++ * } classes[number_of_classes]; ++ * } ++ */ + +- private List classEntries; +- private List stringEntries; ++public class StructInnerClassesAttribute extends StructGeneralAttribute { ++ private List entries; + + @Override + public void initContent(ConstantPool pool) throws IOException { +@@ -34,39 +45,36 @@ public class StructInnerClassesAttribute extends StructGeneralAttribute { + + int len = data.readUnsignedShort(); + if (len > 0) { +- classEntries = new ArrayList(len); +- stringEntries = new ArrayList(len); ++ entries = new ArrayList(); + + for (int i = 0; i < len; i++) { +- int[] classEntry = new int[4]; +- for (int j = 0; j < 4; j++) { +- classEntry[j] = data.readUnsignedShort(); +- } +- classEntries.add(classEntry); +- +- // inner name, enclosing class, original simple name +- String[] stringEntry = new String[3]; +- stringEntry[0] = pool.getPrimitiveConstant(classEntry[0]).getString(); +- if (classEntry[1] != 0) { +- stringEntry[1] = pool.getPrimitiveConstant(classEntry[1]).getString(); +- } +- if (classEntry[2] != 0) { +- stringEntry[2] = pool.getPrimitiveConstant(classEntry[2]).getString(); +- } +- stringEntries.add(stringEntry); ++ entries.add(new InnerClassInfo(data, pool)); + } + } + else { +- classEntries = Collections.emptyList(); +- stringEntries = Collections.emptyList(); ++ entries = Collections.emptyList(); + } + } + +- public List getClassEntries() { +- return classEntries; ++ public List getEntries() { ++ return entries; + } + +- public List getStringEntries() { +- return stringEntries; ++ public static class InnerClassInfo { ++ public String inner_class; ++ public String outer_class; ++ public String inner_name; ++ public int access; ++ ++ private InnerClassInfo(DataInputStream data, ConstantPool pool) throws IOException { ++ this.inner_class = readString(pool, data.readUnsignedShort()); ++ this.outer_class = readString(pool, data.readUnsignedShort()); ++ this.inner_name = readString(pool, data.readUnsignedShort()); ++ this.access = data.readUnsignedShort(); ++ } ++ ++ private String readString(ConstantPool pool, int index) { ++ return index == 0 ? null : pool.getPrimitiveConstant(index).getString(); ++ } + } + } +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0015-Add-new-command-line-argument-sef-SkipExtraFiles-To-.patch b/FernFlower-Patches/0015-Add-new-command-line-argument-sef-SkipExtraFiles-To-.patch deleted file mode 100644 index b9a9f3f..0000000 --- a/FernFlower-Patches/0015-Add-new-command-line-argument-sef-SkipExtraFiles-To-.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Tue, 12 Dec 2017 00:18:19 -0800 -Subject: [PATCH] Add new command line argument -sef SkipExtraFiles: To skip - copying non-class files from the input jars to the output. - - -diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -index 3cbbb19b4dd705f67d0b2450996f704a9e293168..f5fb8fc913c71b38ab0bffb5479d1f49725469ff 100644 ---- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -+++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java -@@ -55,6 +55,8 @@ public interface IFernflowerPreferences { - String USE_JAD_VARNAMING = "jvn"; // Overwrites any Local Variable names with JAD style names - String USE_JAD_PARAMETER_RENAMING = "jpr"; // Include parameter names in JAD naming - -+ String SKIP_EXTRA_FILES = "sef"; -+ - Map DEFAULTS = getDefaults(); - - static Map getDefaults() { -@@ -100,6 +102,7 @@ public interface IFernflowerPreferences { - defaults.put(DUMP_ORIGINAL_LINES, "0"); - defaults.put(USE_JAD_VARNAMING, "0"); - defaults.put(USE_JAD_PARAMETER_RENAMING, "0"); -+ defaults.put(SKIP_EXTRA_FILES, "0"); - - return Collections.unmodifiableMap(defaults); - } -diff --git a/src/org/jetbrains/java/decompiler/struct/ContextUnit.java b/src/org/jetbrains/java/decompiler/struct/ContextUnit.java -index 9482a192692ca6a05d2bb24f3dfca06c25580d80..2d68b9418fcde253948cfa7ffc9c43519884ddce 100644 ---- a/src/org/jetbrains/java/decompiler/struct/ContextUnit.java -+++ b/src/org/jetbrains/java/decompiler/struct/ContextUnit.java -@@ -54,6 +54,8 @@ public class ContextUnit { - } - - public void addOtherEntry(String fullPath, String entry) { -+ if (DecompilerContext.getOption(IFernflowerPreferences.SKIP_EXTRA_FILES)) -+ return; - otherEntries.add(new String[]{fullPath, entry}); - } - -@@ -151,4 +153,4 @@ public class ContextUnit { - public List getClasses() { - return classes; - } --} -\ No newline at end of file -+} diff --git a/FernFlower-Patches/0015-Force-hide-constructors-with-anon-class-as-last-argu.patch b/FernFlower-Patches/0015-Force-hide-constructors-with-anon-class-as-last-argu.patch new file mode 100644 index 0000000..50aecaf --- /dev/null +++ b/FernFlower-Patches/0015-Force-hide-constructors-with-anon-class-as-last-argu.patch @@ -0,0 +1,71 @@ +From 289fb0b9bab3589bef077b002eca23e33fcd1e16 Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Mon, 3 Aug 2015 15:08:26 -0700 +Subject: [PATCH 015/122] Force hide constructors with anon class as last + argument. Java adds these for unknown resons. + +--- + .../java/decompiler/main/ClassWriter.java | 1 + + .../decompiler/main/InitializerProcessor.java | 28 +++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java +index afa2473..3e5789d 100644 +--- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java ++++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java +@@ -60,6 +60,7 @@ public class ClassWriter { + StructClass cl = wrapper.getClassStruct(); + + InitializerProcessor.extractInitializers(wrapper); ++ InitializerProcessor.hideInitalizers(wrapper); + + if (node.type == ClassNode.CLASS_ROOT && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4)) { + ref14processor.processClassReferences(node); +diff --git a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +index e64feea..85d580d 100644 +--- a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java ++++ b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +@@ -25,7 +25,11 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; + import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; + import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; + import org.jetbrains.java.decompiler.struct.StructClass; ++import org.jetbrains.java.decompiler.struct.StructContext; + import org.jetbrains.java.decompiler.struct.StructField; ++import org.jetbrains.java.decompiler.struct.StructMethod; ++import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; ++import org.jetbrains.java.decompiler.struct.gen.VarType; + import org.jetbrains.java.decompiler.util.InterpreterUtil; + + import java.util.ArrayList; +@@ -330,4 +334,28 @@ public class InitializerProcessor { + + return false; + } ++ ++ ++ public static void hideInitalizers(ClassWrapper wrapper) { ++ // hide initializers with anon class arguments ++ for (MethodWrapper method : wrapper.getMethods()) { ++ StructMethod mt = method.methodStruct; ++ String name = mt.getName(); ++ String desc = mt.getDescriptor(); ++ ++ if (mt.isSynthetic() && CodeConstants.INIT_NAME.equals(name)) { ++ MethodDescriptor md = MethodDescriptor.parseDescriptor(desc); ++ if (md.params.length > 0) { ++ VarType type = md.params[md.params.length - 1]; ++ if (type.type == CodeConstants.TYPE_OBJECT) { ++ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(type.value); ++ if (node != null && (node.namelessConstructorStub || node.type == ClassNode.CLASS_ANONYMOUS)) { ++ //TODO: Verify that the body is JUST a this([args]) call? ++ wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(name, desc)); ++ } ++ } ++ } ++ } ++ } ++ } + } +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0016-Bugfix-Fix-invalid-logic-in-ExprUtils.-https-github..patch b/FernFlower-Patches/0016-Bugfix-Fix-invalid-logic-in-ExprUtils.-https-github..patch deleted file mode 100644 index bb011b0..0000000 --- a/FernFlower-Patches/0016-Bugfix-Fix-invalid-logic-in-ExprUtils.-https-github..patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Wed, 21 Feb 2018 18:27:17 -0800 -Subject: [PATCH] Bugfix: Fix invalid logic in ExprUtils. - https://github.com/MinecraftForge/FernFlower/commit/b3171e60c99f1f1a4668b4219e7296139e77f438 - This guy's commit inverted the ACC_STATIC logic. - -The logic was also wrong in that it didn't take the inner class attributes into account either. As it appears that at least the Oracle jdk places the static modifier in in this attribute if the inner class is exposed. - -Example: -public interface Test { - void foo(); - public abstract class Inner { - abstract void bar(); - } -} - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java -index 58a653a79f3dd3215b65b75ccdee314e7e71f3ad..ed7182b90388ba221ca97b6ddd5c640dbc062746 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java -@@ -8,6 +8,9 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; - import org.jetbrains.java.decompiler.main.rels.ClassWrapper; - import org.jetbrains.java.decompiler.main.rels.MethodWrapper; - import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -+import org.jetbrains.java.decompiler.struct.StructClass; -+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; -+import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute; - - import java.util.ArrayList; - import java.util.Collections; -@@ -34,7 +37,7 @@ public final class ExprUtil { - } - mask = methodWrapper.synthParameters; - } -- else if (parameters > 0 && node.type == ClassNode.CLASS_MEMBER && (node.access & CodeConstants.ACC_STATIC) == 0) { -+ else if (parameters > 0 && node.type == ClassNode.CLASS_MEMBER && !isStatic(node.classStruct)) { - // non-static member class - mask = new ArrayList<>(Collections.nCopies(parameters, null)); - mask.set(0, new VarVersionPair(-1, 0)); -@@ -42,4 +45,18 @@ public final class ExprUtil { - - return mask; - } --} -\ No newline at end of file -+ -+ private static boolean isStatic(StructClass struct) { -+ if (struct.hasModifier(CodeConstants.ACC_STATIC)) -+ return true; -+ if (struct.hasAttribute(StructGeneralAttribute.ATTRIBUTE_INNER_CLASSES)) { -+ StructInnerClassesAttribute attr = struct.getAttribute(StructGeneralAttribute.ATTRIBUTE_INNER_CLASSES); -+ for (StructInnerClassesAttribute.Entry entry : attr.getEntries()) { -+ if (entry.innerName != null && entry.innerName.equals(struct.qualifiedName)) { -+ return (entry.accessFlags & CodeConstants.ACC_STATIC) == CodeConstants.ACC_STATIC; -+ } -+ } -+ } -+ return false; -+ } -+} diff --git a/FernFlower-Patches/0016-Fix-JVM-differences-printing-floats-with-an-undefine.patch b/FernFlower-Patches/0016-Fix-JVM-differences-printing-floats-with-an-undefine.patch new file mode 100644 index 0000000..1de4c1c --- /dev/null +++ b/FernFlower-Patches/0016-Fix-JVM-differences-printing-floats-with-an-undefine.patch @@ -0,0 +1,93 @@ +From b44392c8602fca4597fc52d98955a3be4d32ee77 Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Mon, 3 Aug 2015 15:43:39 -0700 +Subject: [PATCH 016/122] Fix JVM differences printing floats with an undefined + number of trailing zeros. (Some JVMs do 0.1F and some do 0.10F) + +--- + .../modules/decompiler/exps/ConstExprent.java | 28 +++++++++++++------ + 1 file changed, 19 insertions(+), 9 deletions(-) + +diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +index 4b9b687..5a751f9 100644 +--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java ++++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +@@ -210,7 +210,7 @@ public class ConstExprent extends Exprent { + doublefield = "MIN_VALUE"; + } + else { +- return new TextBuffer(value.toString()).append("D"); ++ return new TextBuffer(trimZeros(value.toString())).append("D"); + } + return new FieldExprent(doublefield, "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); + case CodeConstants.TYPE_FLOAT: +@@ -247,7 +247,7 @@ public class ConstExprent extends Exprent { + floatfield = "MIN_VALUE"; + } + else { +- return new TextBuffer(value.toString()).append("F"); ++ return new TextBuffer(trimZeros(value.toString())).append("F"); + } + return new FieldExprent(floatfield, "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); + case CodeConstants.TYPE_NULL: +@@ -275,6 +275,16 @@ public class ConstExprent extends Exprent { + throw new RuntimeException("invalid constant type"); + } + ++ private static String trimZeros(String value) { ++ int i = value.length() - 1; ++ while (i >= 0 && value.charAt(i) == '0') { ++ i--; ++ } ++ if (value.charAt(i) == '.') ++ i++; ++ return value.substring(0, i + 1); ++ } ++ + private static String convertStringToJava(String value, boolean ascii) { + char[] arr = value.toCharArray(); + StringBuilder buffer = new StringBuilder(arr.length); +@@ -400,20 +410,20 @@ public class ConstExprent extends Exprent { + public boolean isBoolPermitted() { + return boolPermitted; + } +- ++ + // ***************************************************************************** + // IMatchable implementation + // ***************************************************************************** +- ++ + public boolean match(MatchNode matchNode, MatchEngine engine) { + + if(!super.match(matchNode, engine)) { + return false; + } +- ++ + for(Entry rule : matchNode.getRules().entrySet()) { + RuleValue rule_value = rule.getValue(); +- ++ + switch(rule.getKey()) { + case EXPRENT_CONSTTYPE: + if(!rule_value.value.equals(this.constType)) { +@@ -425,12 +435,12 @@ public class ConstExprent extends Exprent { + if(!engine.checkAndSetVariableValue(rule_value.value.toString(), this.value)) { + return false; + } +- } ++ } + break; + } + } +- ++ + return true; + } +- ++ + } +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0017-Enhance-Generic-Invocations-Temporarily.patch b/FernFlower-Patches/0017-Enhance-Generic-Invocations-Temporarily.patch deleted file mode 100644 index dcd2dfe..0000000 --- a/FernFlower-Patches/0017-Enhance-Generic-Invocations-Temporarily.patch +++ /dev/null @@ -1,268 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Fri, 16 Feb 2018 22:04:00 -0800 -Subject: [PATCH] Enhance Generic Invocations Temporarily. - -This is a temp separate patch until I get some time to merge it to patch 10/13. - -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -index 33150f76d649f124bc818036b0f7c6331d5e74be..e2f36231b51e547b4aae610c8450d83bc0952e44 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java -@@ -266,11 +266,11 @@ public abstract class Exprent implements IMatchable { - protected void wrapInCast(VarType left, VarType right, TextBuffer buf, int precedence) { - boolean needsCast = !left.isSuperset(right) && (right.equals(VarType.VARTYPE_OBJECT) || left.getType() != CodeConstants.TYPE_OBJECT); - -- if (left != null && left.isGeneric()) { -+ if (left.isGeneric() || right.isGeneric()) { - Map> names = this.getNamedGenerics(); - int arrayDim = 0; - -- if (left.getArrayDim() == right.getArrayDim()) { -+ if (left.getArrayDim() == right.getArrayDim() && left.getArrayDim() > 0) { - arrayDim = left.getArrayDim(); - left = left.resizeArrayDim(0); - right = right.resizeArrayDim(0); -diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -index ec2d6931c9426913680fd2ec180483389d96ac4b..cb15c8bc3d924e99c0bf9db350e8fe102bc5f97a 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java -@@ -278,11 +278,11 @@ public class FunctionExprent extends Exprent { - VarType right = lstOperands.get(0).getInferredExprType(upperBound); - VarType cast = lstOperands.get(1).getExprType(); - -- if (upperBound != null && upperBound.isGeneric()) { -+ if (upperBound != null && (upperBound.isGeneric() || right.isGeneric())) { - Map> names = this.getNamedGenerics(); - int arrayDim = 0; - -- if (upperBound.getArrayDim() == right.getArrayDim()) { -+ if (upperBound.getArrayDim() == right.getArrayDim() && upperBound.getArrayDim() > 0) { - arrayDim = upperBound.getArrayDim(); - upperBound = upperBound.resizeArrayDim(0); - right = right.resizeArrayDim(0); -@@ -302,6 +302,15 @@ public class FunctionExprent extends Exprent { - this.needsCast = false; - } - } -+ else { -+ this.needsCast = right.getType() == CodeConstants.TYPE_NULL || !DecompilerContext.getStructContext().instanceOf(right.getValue(), upperBound.getValue()); -+ } -+ if (!this.needsCast) { -+ if (arrayDim > 0) { -+ right = right.resizeArrayDim(arrayDim); -+ } -+ return right; -+ } - } - else { //TODO: Capture generics to make cast better? - this.needsCast = right.getType() == CodeConstants.TYPE_NULL || !DecompilerContext.getStructContext().instanceOf(right.getValue(), cast.getValue()); -@@ -643,4 +652,4 @@ public class FunctionExprent extends Exprent { - Integer type = (Integer)matchNode.getRuleValue(MatchProperties.EXPRENT_FUNCTYPE); - return type == null || this.funcType == type; - } --} -\ 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 d51f0eba4a80cad4159a5135b2d87b8d405c0ed9..f23110233f59728ab4b700bfc0fa2b625f0d7071 100644 ---- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java -@@ -399,6 +399,7 @@ public class InvocationExprent extends Exprent { - isEnum = newNode.classStruct.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); - } - } -+ ClassNode currCls = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE)); - List matches = getMatchedDescriptors(); - BitSet setAmbiguousParameters = getAmbiguousParameters(matches); - StructMethod desc = null; -@@ -459,7 +460,7 @@ public class InvocationExprent extends Exprent { - if (stClass != null) { - nextMethod: - for (StructMethod mt : stClass.getMethods()) { -- if (name.equals(mt.getName())) { -+ if (name.equals(mt.getName()) && (currCls == null || canAccess(currCls.classStruct, mt))) { - MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); - if (md.params.length == descriptor.params.length) { - for (int x = 0; x < md.params.length; x++) { -@@ -494,7 +495,7 @@ public class InvocationExprent extends Exprent { - StructClass stClass = DecompilerContext.getStructContext().getClass(className); - if (stClass != null) { - for (StructMethod mt : stClass.getMethods()) { -- if (name.equals(mt.getName()) && !stringDescriptor.equals(mt.getDescriptor())) { -+ if (name.equals(mt.getName()) && (currCls == null || canAccess(currCls.classStruct, mt)) && !stringDescriptor.equals(mt.getDescriptor())) { - MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); - if (md.params.length == descriptor.params.length) { - if (md.params[i].getType() == CodeConstants.TYPE_OBJECT) { -@@ -511,6 +512,22 @@ public class InvocationExprent extends Exprent { - } - } - -+ if (instance != null && !genArgs.isEmpty()) { -+ StructClass stClass = DecompilerContext.getStructContext().getClass(className); -+ StructMethod me = stClass.getMethodRecursive(getName(), getStringDescriptor()); -+ if (me != null && me.getSignature() != null) { -+ for (int x = 0; x < types.length; x++) { -+ VarType type = me.getSignature().parameterTypes.get(x); -+ if (type.isGeneric()) { -+ VarType _new = type.remap(genArgs); -+ if (_new != type) { -+ types[x] = _new; -+ } -+ } -+ } -+ } -+ } -+ - - boolean firstParameter = true; - for (int i = start; i < this.parameters.size(); i++) { -@@ -665,27 +682,98 @@ public class InvocationExprent extends Exprent { - - private List getMatchedDescriptors() { - List matches = new ArrayList<>(); -+ ClassNode currCls = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE)); - StructClass cl = DecompilerContext.getStructContext().getClass(className); - if (cl == null) return matches; - -- nextMethod: -- for (StructMethod mt : cl.getMethods()) { -- if (name.equals(mt.getName())) { -- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); -- if (md.params.length == descriptor.params.length) { -- for (int i = 0; i < md.params.length; i++) { -- if (md.params[i].getTypeFamily() != descriptor.params[i].getTypeFamily()) { -- continue nextMethod; -- } -+ Set visited = new HashSet<>(); -+ Queue que = new ArrayDeque<>(); -+ que.add(cl); -+ -+ while (!que.isEmpty()) { -+ StructClass cls = que.poll(); -+ if (cls == null) -+ continue; -+ -+ for (StructMethod mt : cls.getMethods()) { -+ if (name.equals(mt.getName())) { -+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); -+ if (matches(md.params, descriptor.params) && (currCls == null || canAccess(currCls.classStruct, mt))) { -+ matches.add(mt); -+ } -+ } -+ } -+ -+ if (cls == cl && !matches.isEmpty()) { -+ return matches; -+ } -+ -+ visited.add(cls.qualifiedName); -+ if (cls.superClass != null && !visited.contains(cls.superClass.value)) { -+ StructClass tmp = DecompilerContext.getStructContext().getClass((String)cls.superClass.value); -+ if (tmp != null) { -+ que.add(tmp); -+ } -+ } -+ -+ for (String intf : cls.getInterfaceNames()) { -+ if (!visited.contains(intf)) { -+ StructClass tmp = DecompilerContext.getStructContext().getClass(intf); -+ if (tmp != null) { -+ que.add(tmp); - } -- matches.add(mt); - } - } -+ - } - - return matches; - } - -+ private boolean matches(VarType[] left, VarType[] right) { -+ if (left.length == right.length) { -+ for (int i = 0; i < left.length; i++) { -+ if (left[i].getTypeFamily() != right[i].getTypeFamily()) { -+ return false; -+ } -+ } -+ return true; -+ } -+ return false; -+ } -+ -+ private boolean canAccess(StructClass currCls, StructMethod mt) { -+ if (mt.hasModifier(CodeConstants.ACC_PUBLIC)) { -+ return true; -+ } -+ else if (mt.hasModifier(CodeConstants.ACC_PRIVATE)) { -+ return mt.getClassQualifiedName().equals(currCls.qualifiedName); -+ } -+ else if (mt.hasModifier(CodeConstants.ACC_PROTECTED)) { -+ boolean samePackage = isInSamePackage(currCls.qualifiedName, mt.getClassQualifiedName()); -+ return samePackage || DecompilerContext.getStructContext().instanceOf(currCls.qualifiedName, mt.getClassQualifiedName()); -+ } -+ else { -+ return isInSamePackage(currCls.qualifiedName, mt.getClassQualifiedName()); -+ } -+ } -+ -+ private boolean isInSamePackage(String class1, String class2) { -+ int pos1 = class1.lastIndexOf('/'); -+ int pos2 = class2.lastIndexOf('/'); -+ if (pos1 != pos2) { -+ return false; -+ } -+ -+ if (pos1 == -1) { -+ return true; -+ } -+ -+ String pkg1 = class1.substring(0, pos1); -+ String pkg2 = class2.substring(0, pos2); -+ return pkg1.equals(pkg2); -+ } -+ - private BitSet getAmbiguousParameters(List matches) { - StructClass cl = DecompilerContext.getStructContext().getClass(className); - if (cl == null || matches.size() == 1) { -diff --git a/src/org/jetbrains/java/decompiler/struct/StructClass.java b/src/org/jetbrains/java/decompiler/struct/StructClass.java -index bead2d172e27075e63f6977562988041a96a4371..4115efedd42ef96e61425d05dc83153e20ebf9a2 100644 ---- a/src/org/jetbrains/java/decompiler/struct/StructClass.java -+++ b/src/org/jetbrains/java/decompiler/struct/StructClass.java -@@ -159,6 +159,35 @@ public class StructClass extends StructMember { - return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor)); - } - -+ public StructMethod getMethodRecursive(String name, String descriptor) { -+ StructMethod ret = getMethod(name, descriptor); -+ -+ if (ret != null) { -+ return ret; -+ } -+ -+ if (superClass != null) { -+ StructClass cls = DecompilerContext.getStructContext().getClass((String)superClass.value); -+ if (cls != null) { -+ ret = cls.getMethodRecursive(name, descriptor); -+ if (ret != null) { -+ return ret; -+ } -+ } -+ } -+ -+ for (String intf : getInterfaceNames()) { -+ StructClass cls = DecompilerContext.getStructContext().getClass(intf); -+ if (cls != null) { -+ ret = cls.getMethodRecursive(name, descriptor); -+ if (ret != null) { -+ return ret; -+ } -+ } -+ } -+ return null; -+ } -+ - public String getInterface(int i) { - return interfaceNames[i]; - } diff --git a/FernFlower-Patches/0017-Sort-local-variables-and-variable-definitions.-Again.patch b/FernFlower-Patches/0017-Sort-local-variables-and-variable-definitions.-Again.patch new file mode 100644 index 0000000..58b407a --- /dev/null +++ b/FernFlower-Patches/0017-Sort-local-variables-and-variable-definitions.-Again.patch @@ -0,0 +1,150 @@ +From 0ecec99fee439f1f018c51826f4105c7753af7f2 Mon Sep 17 00:00:00 2001 +From: Lex Manos +Date: Mon, 3 Aug 2015 17:26:00 -0700 +Subject: [PATCH 017/122] Sort local variables and variable definitions. Again, + different JVMs sort hash sets differently causing different variable names. + +--- + .../modules/decompiler/ExprProcessor.java | 1 + + .../modules/decompiler/exps/Exprent.java | 53 +++++++++++++++---- + .../decompiler/vars/VarVersionsProcessor.java | 11 +++- + 3 files changed, 53 insertions(+), 12 deletions(-) + +diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java +index 9296bb3..205b187 100644 +--- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java ++++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java +@@ -833,6 +833,7 @@ public class ExprProcessor implements CodeConstants { + } + + TextBuffer buf = new TextBuffer(); ++ lst = Exprent.sortIndexed(lst); + + for (Exprent expr : lst) { + TextBuffer content = expr.toJava(indent, tracer); +diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java +index fbd146e..5f2cb56 100644 +--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java ++++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java +@@ -17,6 +17,8 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; + + import java.util.ArrayList; + import java.util.Collection; ++import java.util.Collections; ++import java.util.Comparator; + import java.util.HashSet; + import java.util.List; + import java.util.Map.Entry; +@@ -140,23 +142,23 @@ public class Exprent implements IMatchable { + } + } + } +- ++ + // ***************************************************************************** + // IMatchable implementation + // ***************************************************************************** +- ++ + public IMatchable findObject(MatchNode matchNode, int index) { +- ++ + if(matchNode.getType() != MatchNode.MATCHNODE_EXPRENT) { + return null; + } + + List lstAllExprents = getAllExprents(); +- ++ + if(lstAllExprents == null || lstAllExprents.isEmpty()) { + return null; + } +- ++ + String position = (String)matchNode.getRuleValue(MatchProperties.EXPRENT_POSITION); + if(position != null) { + if(position.matches("-?\\d+")) { +@@ -170,11 +172,11 @@ public class Exprent implements IMatchable { + } + + public boolean match(MatchNode matchNode, MatchEngine engine) { +- ++ + if(matchNode.getType() != MatchNode.MATCHNODE_EXPRENT) { + return false; + } +- ++ + for(Entry rule : matchNode.getRules().entrySet()) { + switch(rule.getKey()) { + case EXPRENT_TYPE: +@@ -188,10 +190,41 @@ public class Exprent implements IMatchable { + } + break; + } +- ++ + } +- ++ + return true; + } +- ++ ++ public static List sortIndexed(List lst) { ++ List ret = new ArrayList(); ++ List defs = new ArrayList(); ++ ++ Comparator comp = new Comparator() { ++ public int compare(VarExprent o1, VarExprent o2) { ++ return o1.getIndex() - o2.getIndex(); ++ } ++ }; ++ ++ for (Exprent exp : lst) { ++ boolean isDef = exp instanceof VarExprent && ((VarExprent)exp).isDefinition(); ++ if (!isDef) { ++ if (defs.size() > 0) { ++ Collections.sort(defs, comp); ++ ret.addAll(defs); ++ defs.clear(); ++ } ++ ret.add(exp); ++ } ++ else { ++ defs.add((VarExprent)exp); ++ } ++ } ++ ++ if (defs.size() > 0) { ++ Collections.sort(defs, comp); ++ ret.addAll(defs); ++ } ++ return ret; ++ } + } +diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java +index 31f0f86..4751052 100644 +--- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java ++++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java +@@ -235,8 +235,15 @@ public class VarVersionsProcessor { + Map mapOriginalVarIndices = new HashMap(); + + // map var-version pairs on new var indexes +- Set set = new HashSet(mapExprentMinTypes.keySet()); +- for (VarVersionPair pair : set) { ++ List lst = new ArrayList(mapExprentMinTypes.keySet()); ++ Collections.sort(lst, new Comparator() { ++ public int compare(VarVersionPair o1, VarVersionPair o2) { ++ if (o1.var != o2.var) return o1.var - o2.var; ++ return o1.version - o2.version; ++ } ++ }); ++ ++ for (VarVersionPair pair : lst) { + + if (pair.version >= 0) { + int newIndex = pair.version == 1 ? pair.var : counters.getCounterAndIncrement(CounterContainer.VAR_COUNTER); +-- +2.21.0.windows.1 + diff --git a/FernFlower-Patches/0018-Add-cfg-argument-Used-to-specify-a-text-file-with-ad.patch b/FernFlower-Patches/0018-Add-cfg-argument-Used-to-specify-a-text-file-with-ad.patch deleted file mode 100644 index 88a608b..0000000 --- a/FernFlower-Patches/0018-Add-cfg-argument-Used-to-specify-a-text-file-with-ad.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LexManos -Date: Fri, 6 Apr 2018 20:45:33 -0700 -Subject: [PATCH] Add -cfg argument Used to specify a text file with additional - command line arguments. - -Our use case is specifying a ton of external libraries. It will read a text file and replace the -cfg entry with those lines. - -diff --git a/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java b/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java -index d0ae9a7c3b20de44cb202390cc0dfd4d690fee64..c5398222893b170023afa13fa5b6c773ab3edc8d 100644 ---- a/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java -+++ b/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java -@@ -10,9 +10,13 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil; - - import java.io.*; - import java.nio.charset.StandardCharsets; -+import java.nio.file.Files; -+import java.nio.file.Path; -+import java.nio.file.Paths; - import java.util.*; - import java.util.jar.JarFile; - import java.util.jar.Manifest; -+import java.util.stream.Stream; - import java.util.zip.ZipEntry; - import java.util.zip.ZipFile; - import java.util.zip.ZipOutputStream; -@@ -20,6 +24,38 @@ import java.util.zip.ZipOutputStream; - public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver { - @SuppressWarnings("UseOfSystemOutOrSystemErr") - public static void main(String[] args) { -+ List params = new ArrayList<>(); -+ for (int x = 0; x < args.length; x++) { -+ if (args[x].startsWith("-cfg")) { -+ String path = null; -+ if (args[x].startsWith("-cfg=")) { -+ path = args[x].substring(5); -+ } -+ else if (args.length > x+1) { -+ path = args[++x]; -+ } -+ else { -+ System.out.println("Must specify a file when using -cfg argument."); -+ return; -+ } -+ Path file = Paths.get(path); -+ if (!Files.exists(file)) { -+ System.out.println("error: missing config '" + path + "'"); -+ return; -+ } -+ try (Stream stream = Files.lines(file)) { -+ stream.forEach(params::add); -+ } catch (IOException e) { -+ System.out.println("error: Failed to read config file '" + path + "'"); -+ throw new RuntimeException(e); -+ } -+ } -+ else { -+ params.add(args[x]); -+ } -+ } -+ args = params.toArray(new String[params.size()]); -+ - if (args.length < 2) { - System.out.println( - "Usage: java -jar fernflower.jar [-