From f54731cc70cab246fce8e840b15be239515ee88f Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Mon, 8 Nov 2021 18:36:49 -0500 Subject: [PATCH 01/85] Bump version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9c3eac6633..943c31e511 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ compileJava { group = 'org.quiltmc' archivesBaseName = 'quiltflower' -version = '1.6.0' +version = '1.7.0' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") From 0f732a3a4680240eb2a144a30d54ba0573fc7c67 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Thu, 11 Nov 2021 08:14:43 -0500 Subject: [PATCH 02/85] Add catch block inlining test --- .../pkg/TestTryWithResourcesCatchJ16.dec | 73 ++++++++++++++++++- .../pkg/TestTryWithResourcesCatchJ16.java | 21 ++++++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/testData/results/pkg/TestTryWithResourcesCatchJ16.dec b/testData/results/pkg/TestTryWithResourcesCatchJ16.dec index 86e559dd8b..0862b55844 100644 --- a/testData/results/pkg/TestTryWithResourcesCatchJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesCatchJ16.dec @@ -22,8 +22,26 @@ public class TestTryWithResourcesCatchJ16 { } }// 22 + public int test1(File file) { + int i = 0;// 25 + + try (Scanner scanner = this.create(file)) {// 28 + scanner.next();// 29 + ++i;// 30 + } catch (Exception var8) { + System.out.println(1);// 33 + if (i == 0) {// 36 + System.out.println(0);// 37 + } else { + System.out.println(2);// 39 + } + + return i;// 42 + } + } + private Scanner create(File file) throws FileNotFoundException { - return new Scanner(file);// 25 + return new Scanner(file);// 46 } } @@ -55,9 +73,46 @@ class 'pkg/TestTryWithResourcesCatchJ16' { 34 22 } + method 'test1 (Ljava/io/File;)I' { + 0 25 + 1 25 + 2 27 + 3 27 + 4 27 + 5 27 + 6 27 + 7 27 + 8 28 + 9 28 + a 28 + b 28 + d 29 + 38 31 + 39 31 + 3a 31 + 3b 31 + 3c 31 + 3f 32 + 40 32 + 43 33 + 44 33 + 45 33 + 46 33 + 47 33 + 48 33 + 49 33 + 4d 35 + 4e 35 + 4f 35 + 50 35 + 51 35 + 54 38 + 55 38 + } + method 'create (Ljava/io/File;)Ljava/util/Scanner;' { - 4 25 - 8 25 + 4 43 + 8 43 } } @@ -72,7 +127,19 @@ Lines mapping: 20 <-> 21 22 <-> 23 25 <-> 26 +28 <-> 28 +29 <-> 29 +30 <-> 30 +33 <-> 32 +36 <-> 33 +37 <-> 34 +39 <-> 36 +42 <-> 39 +46 <-> 44 Not mapped: 13 19 21 +31 +32 +34 diff --git a/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java b/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java index dc42ac26fb..8982c5f79e 100644 --- a/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java +++ b/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java @@ -21,6 +21,27 @@ public void testFunc(File file) { } } + public int test1(File file) { + int i = 0; + + try { + try (Scanner scanner = create(file)) { + scanner.next(); + i++; + } + } catch (Exception e) { + System.out.println(1); + } + + if (i == 0) { + System.out.println(0); + } else { + System.out.println(2); + } + + return i; + } + private Scanner create(File file) throws FileNotFoundException { return new Scanner(file); } From 4845c6c6a3c2cdd8b686388c4ad53c97f2c44bdb Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Thu, 11 Nov 2021 09:22:26 -0500 Subject: [PATCH 03/85] Fix statements being inlined into catch blocks --- .../decompiler/TryWithResourcesProcessor.java | 5 +- .../pkg/TestTryWithResourcesCatchJ16.dec | 144 ++++++++++-------- .../pkg/TestTryWithResourcesCatchJ16.java | 2 + 3 files changed, 86 insertions(+), 65 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java index 6f80a61634..e37cbdc200 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java @@ -255,7 +255,10 @@ public static boolean makeTryWithResourceJ11(CatchStatement tryStatement) { predStat.removeSuccessor(pred); // Connect predecessor of if stat to it's successor, circumventing it - StatEdge newEdge = new StatEdge(StatEdge.TYPE_REGULAR, predStat, successor.getDestination()); + + // When the predecessor is the try statement, we add normal control flow, as the successor is located next to the try statement. When it is not, it must be inside the try, so we break out of it. + // This prevents successor blocks from being inlined, as there are still multiple breaks to the successor and not a singular one that can be inlined [TestTryWithResourcesCatchJ16#test1] + StatEdge newEdge = new StatEdge(predStat == tryStatement ? StatEdge.TYPE_REGULAR : StatEdge.TYPE_BREAK, predStat, successor.getDestination()); predStat.addSuccessor(newEdge); } diff --git a/testData/results/pkg/TestTryWithResourcesCatchJ16.dec b/testData/results/pkg/TestTryWithResourcesCatchJ16.dec index 0862b55844..cb4f3917ec 100644 --- a/testData/results/pkg/TestTryWithResourcesCatchJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesCatchJ16.dec @@ -17,31 +17,37 @@ public class TestTryWithResourcesCatchJ16 { public void testFunc(File file) { try (Scanner scanner = this.create(file)) {// 17 scanner.next();// 18 - } catch (FileNotFoundException var7) { + } catch (FileNotFoundException var7) {// 19 var7.printStackTrace();// 20 } + }// 22 public int test1(File file) { int i = 0;// 25 - try (Scanner scanner = this.create(file)) {// 28 - scanner.next();// 29 - ++i;// 30 - } catch (Exception var8) { - System.out.println(1);// 33 - if (i == 0) {// 36 - System.out.println(0);// 37 - } else { - System.out.println(2);// 39 + try { + System.out.println(-1);// 28 + + try (Scanner scanner = this.create(file)) {// 30 + scanner.next();// 31 + ++i;// 32 } + } catch (Exception var8) {// 34 + System.out.println(1);// 35 + } - return i;// 42 + if (i == 0) {// 38 + System.out.println(0);// 39 + } else { + System.out.println(2);// 41 } + + return i;// 44 } private Scanner create(File file) throws FileNotFoundException { - return new Scanner(file);// 46 + return new Scanner(file);// 48 } } @@ -69,50 +75,59 @@ class 'pkg/TestTryWithResourcesCatchJ16' { 7 18 8 18 9 18 + 2f 19 31 20 - 34 22 + 34 23 } method 'test1 (Ljava/io/File;)I' { - 0 25 - 1 25 - 2 27 - 3 27 - 4 27 - 5 27 - 6 27 - 7 27 - 8 28 - 9 28 - a 28 - b 28 - d 29 - 38 31 - 39 31 - 3a 31 - 3b 31 - 3c 31 - 3f 32 - 40 32 - 43 33 - 44 33 - 45 33 - 46 33 - 47 33 - 48 33 - 49 33 - 4d 35 - 4e 35 - 4f 35 - 50 35 - 51 35 - 54 38 - 55 38 + 0 26 + 1 26 + 2 29 + 3 29 + 4 29 + 5 29 + 6 29 + 7 29 + 8 29 + 9 31 + a 31 + b 31 + c 31 + d 31 + e 31 + f 32 + 10 32 + 11 32 + 12 32 + 14 33 + 3e 35 + 3f 36 + 40 36 + 41 36 + 42 36 + 43 36 + 46 39 + 47 39 + 4a 40 + 4b 40 + 4c 40 + 4d 40 + 4e 40 + 4f 40 + 50 40 + 54 42 + 55 42 + 56 42 + 57 42 + 58 42 + 5b 45 + 5c 45 } method 'create (Ljava/io/File;)Ljava/util/Scanner;' { - 4 43 - 8 43 + 4 49 + 8 49 } } @@ -124,22 +139,23 @@ Lines mapping: 14 <-> 15 17 <-> 18 18 <-> 19 +19 <-> 20 20 <-> 21 -22 <-> 23 -25 <-> 26 -28 <-> 28 -29 <-> 29 -30 <-> 30 -33 <-> 32 -36 <-> 33 -37 <-> 34 -39 <-> 36 -42 <-> 39 -46 <-> 44 +22 <-> 24 +25 <-> 27 +28 <-> 30 +30 <-> 32 +31 <-> 33 +32 <-> 34 +34 <-> 36 +35 <-> 37 +38 <-> 40 +39 <-> 41 +41 <-> 43 +44 <-> 46 +48 <-> 50 Not mapped: 13 -19 21 -31 -32 -34 +33 +36 diff --git a/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java b/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java index 8982c5f79e..d24f7765d6 100644 --- a/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java +++ b/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java @@ -25,6 +25,8 @@ public int test1(File file) { int i = 0; try { + System.out.println(-1); + try (Scanner scanner = create(file)) { scanner.next(); i++; From 2bcb1813b792cac59f67b387c9f5ad2b665aec08 Mon Sep 17 00:00:00 2001 From: Juuxel <6596629+Juuxel@users.noreply.github.com> Date: Fri, 12 Nov 2021 18:34:42 +0200 Subject: [PATCH 04/85] Fix Kotlin appearing in the POM (#51) --- build.gradle | 3 ++- gradle.properties | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 gradle.properties diff --git a/build.gradle b/build.gradle index 943c31e511..c956161298 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,7 @@ dependencies { testDataGroovyImplementation 'org.codehaus.groovy:groovy:3.0.8' testDataKotlinImplementation platform('org.jetbrains.kotlin:kotlin-bom') testDataKotlinImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' + testRuntimeOnly 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' } test { @@ -154,4 +155,4 @@ publishing { } } } -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000..e5d9a95bf5 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +kotlin.stdlib.default.dependency = false From 9ec52abfec943a9b04d7cbb8363e75b33c1e8d82 Mon Sep 17 00:00:00 2001 From: ByMartrixx Date: Fri, 12 Nov 2021 23:18:08 -0300 Subject: [PATCH 05/85] Fix CME with unreferenced local/anonymous classes --- .../java/decompiler/main/rels/NestedClassProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java index cb5c7a3a2a..5de2c393a6 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -99,7 +99,7 @@ else if (child.type != ClassNode.CLASS_MEMBER || (child.access & CodeConstants.A } } - for (ClassNode child : node.nested) { + for (ClassNode child : new ArrayList<>(node.nested)) { processClass(root, child); } } From 188912494b2828952bc15738f8e9bf715f151b9b Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Sat, 13 Nov 2021 17:53:00 +0100 Subject: [PATCH 06/85] Add PPMM tests --- .../java/decompiler/SingleClassesTest.java | 8 + testData/results/pkg/TestPPMM.dec | 335 ++++++++++ testData/results/pkg/TestPPMMBoxed.dec | 629 ++++++++++++++++++ testData/results/pkg/TestPPMMByte.dec | 303 +++++++++ testData/results/pkg/TestPPMMLong.dec | 287 ++++++++ .../results/pkg/TestPPMMOnObjectField.dec | 353 ++++++++++ .../results/pkg/TestPPMMOnStaticField.dec | 321 +++++++++ testData/src/java8/pkg/TestPPMMBoxed.java | 81 +++ testData/src/java8/pkg/TestPPMMByte.java | 81 +++ testData/src/java8/pkg/TestPPMMLong.java | 81 +++ .../src/java8/pkg/TestPPMMOnObjectField.java | 74 +++ .../src/java8/pkg/TestPPMMOnStaticField.java | 74 +++ 12 files changed, 2627 insertions(+) create mode 100644 testData/results/pkg/TestPPMM.dec create mode 100644 testData/results/pkg/TestPPMMBoxed.dec create mode 100644 testData/results/pkg/TestPPMMByte.dec create mode 100644 testData/results/pkg/TestPPMMLong.dec create mode 100644 testData/results/pkg/TestPPMMOnObjectField.dec create mode 100644 testData/results/pkg/TestPPMMOnStaticField.dec create mode 100644 testData/src/java8/pkg/TestPPMMBoxed.java create mode 100644 testData/src/java8/pkg/TestPPMMByte.java create mode 100644 testData/src/java8/pkg/TestPPMMLong.java create mode 100644 testData/src/java8/pkg/TestPPMMOnObjectField.java create mode 100644 testData/src/java8/pkg/TestPPMMOnStaticField.java diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index e4d23e7fa7..7174877b78 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -375,6 +375,14 @@ private void registerDefault() { register(JAVA_8, "TestUnicodeIdentifiers"); register(JAVA_8, "TestDoubleBraceInitializers"); + + + register(JAVA_8, "TestPPMM"); + register(JAVA_8, "TestPPMMByte"); + register(JAVA_8, "TestPPMMLong"); + register(JAVA_8, "TestPPMMBoxed"); + register(JAVA_8, "TestPPMMOnObjectField"); + register(JAVA_8, "TestPPMMOnStaticField"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestPPMM.dec b/testData/results/pkg/TestPPMM.dec new file mode 100644 index 0000000000..c5f22f39b0 --- /dev/null +++ b/testData/results/pkg/TestPPMM.dec @@ -0,0 +1,335 @@ +package pkg; + +public class TestPPMM { + public void ipp() { + int a = 0;// 22 + ++a;// 23 + ++a;// 24 + ++a;// 25 + ++a;// 26 + }// 27 + + public void ppi() { + int a = 0;// 29 + ++a;// 30 + ++a;// 31 + ++a;// 32 + ++a;// 33 + }// 34 + + public void imm() { + int a = 0;// 36 + --a;// 37 + --a;// 38 + --a;// 39 + --a;// 40 + }// 41 + + public void mmi() { + int a = 0;// 43 + --a;// 44 + --a;// 45 + --a;// 46 + --a;// 47 + }// 48 + + public void ippf() { + int a = 0;// 52 + t(a++);// 53 + t(a++);// 54 + t(a++);// 55 + t(a++);// 56 + }// 57 + + public void ppif() { + int a = 0;// 59 + ++a;// 60 + t(a); + ++a;// 61 + t(a); + ++a;// 62 + t(a); + ++a;// 63 + t(a); + }// 64 + + public void immf() { + int a = 0;// 66 + t(a--);// 67 + t(a--);// 68 + t(a--);// 69 + t(a--);// 70 + }// 71 + + public void mmif() { + int a = 0;// 73 + --a;// 74 + t(a); + --a;// 75 + t(a); + --a;// 76 + t(a); + --a;// 77 + t(a); + }// 78 + + private static void t(int x) { + }// 80 +} + +class 'pkg/TestPPMM' { + method 'ipp ()V' { + 0 4 + 1 4 + 2 5 + 3 5 + 4 5 + 5 6 + 6 6 + 7 6 + 8 7 + 9 7 + a 7 + b 8 + c 8 + d 8 + e 9 + } + + method 'ppi ()V' { + 0 12 + 1 12 + 2 13 + 3 13 + 4 13 + 5 14 + 6 14 + 7 14 + 8 15 + 9 15 + a 15 + b 16 + c 16 + d 16 + e 17 + } + + method 'imm ()V' { + 0 20 + 1 20 + 2 21 + 3 21 + 4 21 + 5 22 + 6 22 + 7 22 + 8 23 + 9 23 + a 23 + b 24 + c 24 + d 24 + e 25 + } + + method 'mmi ()V' { + 0 28 + 1 28 + 2 29 + 3 29 + 4 29 + 5 30 + 6 30 + 7 30 + 8 31 + 9 31 + a 31 + b 32 + c 32 + d 32 + e 33 + } + + method 'ippf ()V' { + 0 36 + 1 36 + 3 37 + 4 37 + 5 37 + 6 37 + 7 37 + 8 37 + a 38 + b 38 + c 38 + d 38 + e 38 + f 38 + 11 39 + 12 39 + 13 39 + 14 39 + 15 39 + 16 39 + 18 40 + 19 40 + 1a 40 + 1b 40 + 1c 40 + 1d 40 + 1e 41 + } + + method 'ppif ()V' { + 0 44 + 1 44 + 2 45 + 3 45 + 4 45 + 5 46 + 6 46 + 7 46 + 8 46 + 9 47 + a 47 + b 47 + c 48 + d 48 + e 48 + f 48 + 10 49 + 11 49 + 12 49 + 13 50 + 14 50 + 15 50 + 16 50 + 17 51 + 18 51 + 19 51 + 1a 52 + 1b 52 + 1c 52 + 1d 52 + 1e 53 + } + + method 'immf ()V' { + 0 56 + 1 56 + 3 57 + 4 57 + 5 57 + 6 57 + 7 57 + 8 57 + a 58 + b 58 + c 58 + d 58 + e 58 + f 58 + 11 59 + 12 59 + 13 59 + 14 59 + 15 59 + 16 59 + 18 60 + 19 60 + 1a 60 + 1b 60 + 1c 60 + 1d 60 + 1e 61 + } + + method 'mmif ()V' { + 0 64 + 1 64 + 2 65 + 3 65 + 4 65 + 5 66 + 6 66 + 7 66 + 8 66 + 9 67 + a 67 + b 67 + c 68 + d 68 + e 68 + f 68 + 10 69 + 11 69 + 12 69 + 13 70 + 14 70 + 15 70 + 16 70 + 17 71 + 18 71 + 19 71 + 1a 72 + 1b 72 + 1c 72 + 1d 72 + 1e 73 + } + + method 't (I)V' { + 0 76 + } +} + +Lines mapping: +22 <-> 5 +23 <-> 6 +24 <-> 7 +25 <-> 8 +26 <-> 9 +27 <-> 10 +29 <-> 13 +30 <-> 14 +31 <-> 15 +32 <-> 16 +33 <-> 17 +34 <-> 18 +36 <-> 21 +37 <-> 22 +38 <-> 23 +39 <-> 24 +40 <-> 25 +41 <-> 26 +43 <-> 29 +44 <-> 30 +45 <-> 31 +46 <-> 32 +47 <-> 33 +48 <-> 34 +52 <-> 37 +53 <-> 38 +54 <-> 39 +55 <-> 40 +56 <-> 41 +57 <-> 42 +59 <-> 45 +60 <-> 46 +61 <-> 48 +62 <-> 50 +63 <-> 52 +64 <-> 54 +66 <-> 57 +67 <-> 58 +68 <-> 59 +69 <-> 60 +70 <-> 61 +71 <-> 62 +73 <-> 65 +74 <-> 66 +75 <-> 68 +76 <-> 70 +77 <-> 72 +78 <-> 74 +80 <-> 77 diff --git a/testData/results/pkg/TestPPMMBoxed.dec b/testData/results/pkg/TestPPMMBoxed.dec new file mode 100644 index 0000000000..ae1d92f48c --- /dev/null +++ b/testData/results/pkg/TestPPMMBoxed.dec @@ -0,0 +1,629 @@ +package pkg; + +public class TestPPMMBoxed { + public void ipp() { + Integer a = 0;// 22 + a = a + 1;// 23 + a = a + 1;// 24 + a = a + 1;// 25 + a + 1;// 26 + }// 27 + + public void ppi() { + Integer a = 0;// 29 + a = a + 1;// 30 + a = a + 1;// 31 + a = a + 1;// 32 + a = a + 1;// 33 + }// 34 + + public void imm() { + Integer a = 0;// 36 + a = a - 1;// 37 + a = a - 1;// 38 + a = a - 1;// 39 + a - 1;// 40 + }// 41 + + public void mmi() { + Integer a = 0;// 43 + a = a - 1;// 44 + a = a - 1;// 45 + a = a - 1;// 46 + a = a - 1;// 47 + }// 48 + + public void ippf() { + Integer a = 0;// 52 + Integer var4 = a + 1; + t(a);// 53 + a = var4 + 1; + t(var4);// 54 + Integer var6 = a + 1; + t(a);// 55 + var6 + 1; + t(var6);// 56 + }// 57 + + public void ppif() { + Integer a = 0;// 59 + Integer var2; + t(var2 = a + 1);// 60 + t(a = var2 + 1);// 61 + Integer var4; + t(var4 = a + 1);// 62 + t(Integer.valueOf(var4 + 1));// 63 + }// 64 + + public void immf() { + Integer a = 0;// 66 + Integer var4 = a - 1; + t(a);// 67 + a = var4 - 1; + t(var4);// 68 + Integer var6 = a - 1; + t(a);// 69 + var6 - 1; + t(var6);// 70 + }// 71 + + public void mmif() { + Integer a = 0;// 73 + Integer var2; + t(var2 = a - 1);// 74 + t(a = var2 - 1);// 75 + Integer var4; + t(var4 = a - 1);// 76 + t(Integer.valueOf(var4 - 1));// 77 + }// 78 + + private static void t(int x) { + }// 80 +} + +class 'pkg/TestPPMMBoxed' { + method 'ipp ()V' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 7 5 + 8 5 + 9 5 + a 5 + b 5 + c 5 + d 5 + e 5 + f 5 + 11 5 + 17 6 + 18 6 + 19 6 + 1a 6 + 1b 6 + 1c 6 + 1d 6 + 1e 6 + 1f 6 + 21 6 + 27 7 + 28 7 + 29 7 + 2a 7 + 2b 7 + 2c 7 + 2d 7 + 2e 7 + 2f 7 + 31 7 + 37 8 + 38 8 + 39 8 + 3a 8 + 3b 8 + 3c 8 + 3d 8 + 3e 8 + 3f 8 + 45 9 + } + + method 'ppi ()V' { + 0 12 + 1 12 + 2 12 + 3 12 + 4 12 + 5 13 + 6 13 + 7 13 + 8 13 + 9 13 + a 13 + b 13 + c 13 + d 13 + e 13 + f 14 + 10 14 + 11 14 + 12 14 + 13 14 + 14 14 + 15 14 + 16 14 + 17 14 + 18 14 + 19 15 + 1a 15 + 1b 15 + 1c 15 + 1d 15 + 1e 15 + 1f 15 + 20 15 + 21 15 + 22 15 + 23 16 + 24 16 + 25 16 + 26 16 + 27 16 + 28 16 + 29 16 + 2a 16 + 2b 16 + 2c 16 + 2d 17 + } + + method 'imm ()V' { + 0 20 + 1 20 + 2 20 + 3 20 + 4 20 + 7 21 + 8 21 + 9 21 + a 21 + b 21 + c 21 + d 21 + e 21 + f 21 + 11 21 + 17 22 + 18 22 + 19 22 + 1a 22 + 1b 22 + 1c 22 + 1d 22 + 1e 22 + 1f 22 + 21 22 + 27 23 + 28 23 + 29 23 + 2a 23 + 2b 23 + 2c 23 + 2d 23 + 2e 23 + 2f 23 + 31 23 + 37 24 + 38 24 + 39 24 + 3a 24 + 3b 24 + 3c 24 + 3d 24 + 3e 24 + 3f 24 + 45 25 + } + + method 'mmi ()V' { + 0 28 + 1 28 + 2 28 + 3 28 + 4 28 + 5 29 + 6 29 + 7 29 + 8 29 + 9 29 + a 29 + b 29 + c 29 + d 29 + e 29 + f 30 + 10 30 + 11 30 + 12 30 + 13 30 + 14 30 + 15 30 + 16 30 + 17 30 + 18 30 + 19 31 + 1a 31 + 1b 31 + 1c 31 + 1d 31 + 1e 31 + 1f 31 + 20 31 + 21 31 + 22 31 + 23 32 + 24 32 + 25 32 + 26 32 + 27 32 + 28 32 + 29 32 + 2a 32 + 2b 32 + 2c 32 + 2d 33 + } + + method 'ippf ()V' { + 0 36 + 1 36 + 2 36 + 3 36 + 4 36 + 5 38 + 7 37 + 8 37 + 9 37 + a 37 + b 37 + c 37 + d 37 + e 37 + f 37 + 11 37 + 14 38 + 15 38 + 16 38 + 17 38 + 18 38 + 19 38 + 1a 40 + 1c 39 + 1d 39 + 1e 39 + 1f 39 + 20 39 + 21 39 + 22 39 + 23 39 + 24 39 + 26 39 + 29 40 + 2a 40 + 2b 40 + 2c 40 + 2d 40 + 2e 40 + 2f 42 + 31 41 + 32 41 + 33 41 + 34 41 + 35 41 + 36 41 + 37 41 + 38 41 + 39 41 + 3b 41 + 3e 42 + 3f 42 + 40 42 + 41 42 + 42 42 + 43 42 + 44 44 + 46 43 + 47 43 + 48 43 + 49 43 + 4a 43 + 4b 43 + 4c 43 + 4d 43 + 4e 43 + 53 44 + 54 44 + 55 44 + 56 44 + 57 44 + 58 44 + 59 45 + } + + method 'ppif ()V' { + 0 48 + 1 48 + 2 48 + 3 48 + 4 48 + 5 50 + 6 50 + 7 50 + 8 50 + 9 50 + a 50 + b 50 + c 50 + d 50 + f 50 + 10 50 + 11 50 + 12 50 + 13 50 + 14 50 + 15 50 + 16 51 + 17 51 + 18 51 + 19 51 + 1a 51 + 1b 51 + 1c 51 + 1d 51 + 1e 51 + 20 51 + 21 51 + 22 51 + 23 51 + 24 51 + 25 51 + 26 51 + 27 53 + 28 53 + 29 53 + 2a 53 + 2b 53 + 2c 53 + 2d 53 + 2e 53 + 2f 53 + 31 53 + 32 53 + 33 53 + 34 53 + 35 53 + 36 53 + 37 53 + 38 54 + 39 54 + 3a 54 + 3b 54 + 3c 54 + 3d 54 + 3e 54 + 3f 54 + 40 54 + 43 54 + 44 54 + 45 54 + 46 54 + 47 54 + 48 54 + 49 55 + } + + method 'immf ()V' { + 0 58 + 1 58 + 2 58 + 3 58 + 4 58 + 5 60 + 7 59 + 8 59 + 9 59 + a 59 + b 59 + c 59 + d 59 + e 59 + f 59 + 11 59 + 14 60 + 15 60 + 16 60 + 17 60 + 18 60 + 19 60 + 1a 62 + 1c 61 + 1d 61 + 1e 61 + 1f 61 + 20 61 + 21 61 + 22 61 + 23 61 + 24 61 + 26 61 + 29 62 + 2a 62 + 2b 62 + 2c 62 + 2d 62 + 2e 62 + 2f 64 + 31 63 + 32 63 + 33 63 + 34 63 + 35 63 + 36 63 + 37 63 + 38 63 + 39 63 + 3b 63 + 3e 64 + 3f 64 + 40 64 + 41 64 + 42 64 + 43 64 + 44 66 + 46 65 + 47 65 + 48 65 + 49 65 + 4a 65 + 4b 65 + 4c 65 + 4d 65 + 4e 65 + 53 66 + 54 66 + 55 66 + 56 66 + 57 66 + 58 66 + 59 67 + } + + method 'mmif ()V' { + 0 70 + 1 70 + 2 70 + 3 70 + 4 70 + 5 72 + 6 72 + 7 72 + 8 72 + 9 72 + a 72 + b 72 + c 72 + d 72 + f 72 + 10 72 + 11 72 + 12 72 + 13 72 + 14 72 + 15 72 + 16 73 + 17 73 + 18 73 + 19 73 + 1a 73 + 1b 73 + 1c 73 + 1d 73 + 1e 73 + 20 73 + 21 73 + 22 73 + 23 73 + 24 73 + 25 73 + 26 73 + 27 75 + 28 75 + 29 75 + 2a 75 + 2b 75 + 2c 75 + 2d 75 + 2e 75 + 2f 75 + 31 75 + 32 75 + 33 75 + 34 75 + 35 75 + 36 75 + 37 75 + 38 76 + 39 76 + 3a 76 + 3b 76 + 3c 76 + 3d 76 + 3e 76 + 3f 76 + 40 76 + 43 76 + 44 76 + 45 76 + 46 76 + 47 76 + 48 76 + 49 77 + } + + method 't (I)V' { + 0 80 + } +} + +Lines mapping: +22 <-> 5 +23 <-> 6 +24 <-> 7 +25 <-> 8 +26 <-> 9 +27 <-> 10 +29 <-> 13 +30 <-> 14 +31 <-> 15 +32 <-> 16 +33 <-> 17 +34 <-> 18 +36 <-> 21 +37 <-> 22 +38 <-> 23 +39 <-> 24 +40 <-> 25 +41 <-> 26 +43 <-> 29 +44 <-> 30 +45 <-> 31 +46 <-> 32 +47 <-> 33 +48 <-> 34 +52 <-> 37 +53 <-> 39 +54 <-> 41 +55 <-> 43 +56 <-> 45 +57 <-> 46 +59 <-> 49 +60 <-> 51 +61 <-> 52 +62 <-> 54 +63 <-> 55 +64 <-> 56 +66 <-> 59 +67 <-> 61 +68 <-> 63 +69 <-> 65 +70 <-> 67 +71 <-> 68 +73 <-> 71 +74 <-> 73 +75 <-> 74 +76 <-> 76 +77 <-> 77 +78 <-> 78 +80 <-> 81 diff --git a/testData/results/pkg/TestPPMMByte.dec b/testData/results/pkg/TestPPMMByte.dec new file mode 100644 index 0000000000..1e0d771fd7 --- /dev/null +++ b/testData/results/pkg/TestPPMMByte.dec @@ -0,0 +1,303 @@ +package pkg; + +public class TestPPMMByte { + public void ipp() { + byte a = 0;// 22 + ++a;// 23 + ++a;// 24 + ++a;// 25 + ++a;// 26 + }// 27 + + public void ppi() { + byte a = 0;// 29 + ++a;// 30 + ++a;// 31 + ++a;// 32 + ++a;// 33 + }// 34 + + public void imm() { + byte a = 0;// 36 + --a;// 37 + --a;// 38 + --a;// 39 + --a;// 40 + }// 41 + + public void mmi() { + byte a = 0;// 43 + --a;// 44 + --a;// 45 + --a;// 46 + --a;// 47 + }// 48 + + public void ippf() { + byte a = 0;// 52 + t(a++);// 53 + t(a++);// 54 + t(a++);// 55 + t(a++);// 56 + }// 57 + + public void ppif() { + byte a = 0;// 59 + ++a;// 60 + t(a); + ++a;// 61 + t(a); + ++a;// 62 + t(a); + ++a;// 63 + t(a); + }// 64 + + public void immf() { + byte a = 0;// 66 + t(a--);// 67 + t(a--);// 68 + t(a--);// 69 + t(a--);// 70 + }// 71 + + public void mmif() { + byte a = 0;// 73 + --a;// 74 + t(a); + --a;// 75 + t(a); + --a;// 76 + t(a); + --a;// 77 + t(a); + }// 78 + + private static void t(byte x) { + }// 80 +} + +class 'pkg/TestPPMMByte' { + method 'ipp ()V' { + 0 4 + 1 4 + 2 5 + 4 5 + 7 6 + 9 6 + c 7 + e 7 + 11 8 + 13 8 + 16 9 + } + + method 'ppi ()V' { + 0 12 + 1 12 + 2 13 + 4 13 + 7 14 + 9 14 + c 15 + e 15 + 11 16 + 13 16 + 16 17 + } + + method 'imm ()V' { + 0 20 + 1 20 + 2 21 + 4 21 + 7 22 + 9 22 + c 23 + e 23 + 11 24 + 13 24 + 16 25 + } + + method 'mmi ()V' { + 0 28 + 1 28 + 2 29 + 4 29 + 7 30 + 9 30 + c 31 + e 31 + 11 32 + 13 32 + 16 33 + } + + method 'ippf ()V' { + 0 36 + 1 36 + 3 37 + 5 37 + 8 37 + 9 37 + a 37 + c 38 + e 38 + 11 38 + 12 38 + 13 38 + 15 39 + 17 39 + 1a 39 + 1b 39 + 1c 39 + 1e 40 + 20 40 + 23 40 + 24 40 + 25 40 + 26 41 + } + + method 'ppif ()V' { + 0 44 + 1 44 + 2 45 + 4 45 + 7 46 + 8 46 + 9 46 + a 46 + b 47 + d 47 + 10 48 + 11 48 + 12 48 + 13 48 + 14 49 + 16 49 + 19 50 + 1a 50 + 1b 50 + 1c 50 + 1d 51 + 1f 51 + 22 52 + 23 52 + 24 52 + 25 52 + 26 53 + } + + method 'immf ()V' { + 0 56 + 1 56 + 3 57 + 5 57 + 8 57 + 9 57 + a 57 + c 58 + e 58 + 11 58 + 12 58 + 13 58 + 15 59 + 17 59 + 1a 59 + 1b 59 + 1c 59 + 1e 60 + 20 60 + 23 60 + 24 60 + 25 60 + 26 61 + } + + method 'mmif ()V' { + 0 64 + 1 64 + 2 65 + 4 65 + 7 66 + 8 66 + 9 66 + a 66 + b 67 + d 67 + 10 68 + 11 68 + 12 68 + 13 68 + 14 69 + 16 69 + 19 70 + 1a 70 + 1b 70 + 1c 70 + 1d 71 + 1f 71 + 22 72 + 23 72 + 24 72 + 25 72 + 26 73 + } + + method 't (B)V' { + 0 76 + } +} + +Lines mapping: +22 <-> 5 +23 <-> 6 +24 <-> 7 +25 <-> 8 +26 <-> 9 +27 <-> 10 +29 <-> 13 +30 <-> 14 +31 <-> 15 +32 <-> 16 +33 <-> 17 +34 <-> 18 +36 <-> 21 +37 <-> 22 +38 <-> 23 +39 <-> 24 +40 <-> 25 +41 <-> 26 +43 <-> 29 +44 <-> 30 +45 <-> 31 +46 <-> 32 +47 <-> 33 +48 <-> 34 +52 <-> 37 +53 <-> 38 +54 <-> 39 +55 <-> 40 +56 <-> 41 +57 <-> 42 +59 <-> 45 +60 <-> 46 +61 <-> 48 +62 <-> 50 +63 <-> 52 +64 <-> 54 +66 <-> 57 +67 <-> 58 +68 <-> 59 +69 <-> 60 +70 <-> 61 +71 <-> 62 +73 <-> 65 +74 <-> 66 +75 <-> 68 +76 <-> 70 +77 <-> 72 +78 <-> 74 +80 <-> 77 diff --git a/testData/results/pkg/TestPPMMLong.dec b/testData/results/pkg/TestPPMMLong.dec new file mode 100644 index 0000000000..f2e6ce5c32 --- /dev/null +++ b/testData/results/pkg/TestPPMMLong.dec @@ -0,0 +1,287 @@ +package pkg; + +public class TestPPMMLong { + public void ipp() { + long a = 0L;// 22 + ++a;// 23 + ++a;// 24 + ++a;// 25 + ++a;// 26 + }// 27 + + public void ppi() { + long a = 0L;// 29 + ++a;// 30 + ++a;// 31 + ++a;// 32 + ++a;// 33 + }// 34 + + public void imm() { + long a = 0L;// 36 + --a;// 37 + --a;// 38 + --a;// 39 + --a;// 40 + }// 41 + + public void mmi() { + long a = 0L;// 43 + --a;// 44 + --a;// 45 + --a;// 46 + --a;// 47 + }// 48 + + public void ippf() { + long a = 0L;// 52 + t(a++);// 53 + t(a++);// 54 + t(a++);// 55 + t(a++);// 56 + }// 57 + + public void ppif() { + long a = 0L;// 59 + t(++a);// 60 + t(++a);// 61 + t(++a);// 62 + t(++a);// 63 + }// 64 + + public void immf() { + long a = 0L;// 66 + t(a--);// 67 + t(a--);// 68 + t(a--);// 69 + t(a--);// 70 + }// 71 + + public void mmif() { + long a = 0L;// 73 + t(--a);// 74 + t(--a);// 75 + t(--a);// 76 + t(--a);// 77 + }// 78 + + private static void t(long x) { + }// 80 +} + +class 'pkg/TestPPMMLong' { + method 'ipp ()V' { + 0 4 + 1 4 + 2 5 + 4 5 + 6 6 + 8 6 + a 7 + c 7 + e 8 + 10 8 + 12 9 + } + + method 'ppi ()V' { + 0 12 + 1 12 + 2 13 + 4 13 + 6 14 + 8 14 + a 15 + c 15 + e 16 + 10 16 + 12 17 + } + + method 'imm ()V' { + 0 20 + 1 20 + 2 21 + 4 21 + 6 22 + 8 22 + a 23 + c 23 + e 24 + 10 24 + 12 25 + } + + method 'mmi ()V' { + 0 28 + 1 28 + 2 29 + 4 29 + 6 30 + 8 30 + a 31 + c 31 + e 32 + 10 32 + 12 33 + } + + method 'ippf ()V' { + 0 36 + 1 36 + 2 37 + 5 37 + 7 37 + 8 37 + 9 37 + a 38 + d 38 + f 38 + 10 38 + 11 38 + 12 39 + 15 39 + 17 39 + 18 39 + 19 39 + 1a 40 + 1d 40 + 1f 40 + 20 40 + 21 40 + 22 41 + } + + method 'ppif ()V' { + 0 44 + 1 44 + 2 45 + 4 45 + 7 45 + 8 45 + 9 45 + a 46 + c 46 + f 46 + 10 46 + 11 46 + 12 47 + 14 47 + 17 47 + 18 47 + 19 47 + 1a 48 + 1c 48 + 1f 48 + 20 48 + 21 48 + 22 49 + } + + method 'immf ()V' { + 0 52 + 1 52 + 2 53 + 5 53 + 7 53 + 8 53 + 9 53 + a 54 + d 54 + f 54 + 10 54 + 11 54 + 12 55 + 15 55 + 17 55 + 18 55 + 19 55 + 1a 56 + 1d 56 + 1f 56 + 20 56 + 21 56 + 22 57 + } + + method 'mmif ()V' { + 0 60 + 1 60 + 2 61 + 4 61 + 7 61 + 8 61 + 9 61 + a 62 + c 62 + f 62 + 10 62 + 11 62 + 12 63 + 14 63 + 17 63 + 18 63 + 19 63 + 1a 64 + 1c 64 + 1f 64 + 20 64 + 21 64 + 22 65 + } + + method 't (J)V' { + 0 68 + } +} + +Lines mapping: +22 <-> 5 +23 <-> 6 +24 <-> 7 +25 <-> 8 +26 <-> 9 +27 <-> 10 +29 <-> 13 +30 <-> 14 +31 <-> 15 +32 <-> 16 +33 <-> 17 +34 <-> 18 +36 <-> 21 +37 <-> 22 +38 <-> 23 +39 <-> 24 +40 <-> 25 +41 <-> 26 +43 <-> 29 +44 <-> 30 +45 <-> 31 +46 <-> 32 +47 <-> 33 +48 <-> 34 +52 <-> 37 +53 <-> 38 +54 <-> 39 +55 <-> 40 +56 <-> 41 +57 <-> 42 +59 <-> 45 +60 <-> 46 +61 <-> 47 +62 <-> 48 +63 <-> 49 +64 <-> 50 +66 <-> 53 +67 <-> 54 +68 <-> 55 +69 <-> 56 +70 <-> 57 +71 <-> 58 +73 <-> 61 +74 <-> 62 +75 <-> 63 +76 <-> 64 +77 <-> 65 +78 <-> 66 +80 <-> 69 diff --git a/testData/results/pkg/TestPPMMOnObjectField.dec b/testData/results/pkg/TestPPMMOnObjectField.dec new file mode 100644 index 0000000000..943b518322 --- /dev/null +++ b/testData/results/pkg/TestPPMMOnObjectField.dec @@ -0,0 +1,353 @@ +package pkg; + +public class TestPPMMOnObjectField { + int a; + + public void ipp() { + ++this.a;// 23 + ++this.a;// 24 + ++this.a;// 25 + ++this.a;// 26 + }// 27 + + public void ppi() { + ++this.a;// 29 + ++this.a;// 30 + ++this.a;// 31 + ++this.a;// 32 + }// 33 + + public void imm() { + --this.a;// 35 + --this.a;// 36 + --this.a;// 37 + --this.a;// 38 + }// 39 + + public void mmi() { + --this.a;// 41 + --this.a;// 42 + --this.a;// 43 + --this.a;// 44 + }// 45 + + public void ippf() { + t(this.a++);// 49 + t(this.a++);// 50 + t(this.a++);// 51 + t(this.a++);// 52 + }// 53 + + public void ppif() { + t(++this.a);// 55 + t(++this.a);// 56 + t(++this.a);// 57 + t(++this.a);// 58 + }// 59 + + public void immf() { + t(this.a--);// 61 + t(this.a--);// 62 + t(this.a--);// 63 + t(this.a--);// 64 + }// 65 + + public void mmif() { + t(--this.a);// 67 + t(--this.a);// 68 + t(--this.a);// 69 + t(--this.a);// 70 + }// 71 + + private static void t(int x) { + }// 73 +} + +class 'pkg/TestPPMMOnObjectField' { + method 'ipp ()V' { + 0 6 + 2 6 + 3 6 + 4 6 + 6 6 + a 7 + c 7 + d 7 + e 7 + 10 7 + 14 8 + 16 8 + 17 8 + 18 8 + 1a 8 + 1e 9 + 20 9 + 21 9 + 22 9 + 24 9 + 28 10 + } + + method 'ppi ()V' { + 0 13 + 2 13 + 3 13 + 4 13 + 6 13 + a 14 + c 14 + d 14 + e 14 + 10 14 + 14 15 + 16 15 + 17 15 + 18 15 + 1a 15 + 1e 16 + 20 16 + 21 16 + 22 16 + 24 16 + 28 17 + } + + method 'imm ()V' { + 0 20 + 2 20 + 3 20 + 4 20 + 6 20 + a 21 + c 21 + d 21 + e 21 + 10 21 + 14 22 + 16 22 + 17 22 + 18 22 + 1a 22 + 1e 23 + 20 23 + 21 23 + 22 23 + 24 23 + 28 24 + } + + method 'mmi ()V' { + 0 27 + 2 27 + 3 27 + 4 27 + 6 27 + a 28 + c 28 + d 28 + e 28 + 10 28 + 14 29 + 16 29 + 17 29 + 18 29 + 1a 29 + 1e 30 + 20 30 + 21 30 + 22 30 + 24 30 + 28 31 + } + + method 'ippf ()V' { + 0 34 + 2 34 + 3 34 + 4 34 + 7 34 + b 34 + c 34 + d 34 + e 35 + 10 35 + 11 35 + 12 35 + 15 35 + 19 35 + 1a 35 + 1b 35 + 1c 36 + 1e 36 + 1f 36 + 20 36 + 23 36 + 27 36 + 28 36 + 29 36 + 2a 37 + 2c 37 + 2d 37 + 2e 37 + 31 37 + 35 37 + 36 37 + 37 37 + 38 38 + } + + method 'ppif ()V' { + 0 41 + 2 41 + 3 41 + 4 41 + 6 41 + b 41 + c 41 + d 41 + e 42 + 10 42 + 11 42 + 12 42 + 14 42 + 19 42 + 1a 42 + 1b 42 + 1c 43 + 1e 43 + 1f 43 + 20 43 + 22 43 + 27 43 + 28 43 + 29 43 + 2a 44 + 2c 44 + 2d 44 + 2e 44 + 30 44 + 35 44 + 36 44 + 37 44 + 38 45 + } + + method 'immf ()V' { + 0 48 + 2 48 + 3 48 + 4 48 + 7 48 + b 48 + c 48 + d 48 + e 49 + 10 49 + 11 49 + 12 49 + 15 49 + 19 49 + 1a 49 + 1b 49 + 1c 50 + 1e 50 + 1f 50 + 20 50 + 23 50 + 27 50 + 28 50 + 29 50 + 2a 51 + 2c 51 + 2d 51 + 2e 51 + 31 51 + 35 51 + 36 51 + 37 51 + 38 52 + } + + method 'mmif ()V' { + 0 55 + 2 55 + 3 55 + 4 55 + 6 55 + b 55 + c 55 + d 55 + e 56 + 10 56 + 11 56 + 12 56 + 14 56 + 19 56 + 1a 56 + 1b 56 + 1c 57 + 1e 57 + 1f 57 + 20 57 + 22 57 + 27 57 + 28 57 + 29 57 + 2a 58 + 2c 58 + 2d 58 + 2e 58 + 30 58 + 35 58 + 36 58 + 37 58 + 38 59 + } + + method 't (I)V' { + 0 62 + } +} + +Lines mapping: +23 <-> 7 +24 <-> 8 +25 <-> 9 +26 <-> 10 +27 <-> 11 +29 <-> 14 +30 <-> 15 +31 <-> 16 +32 <-> 17 +33 <-> 18 +35 <-> 21 +36 <-> 22 +37 <-> 23 +38 <-> 24 +39 <-> 25 +41 <-> 28 +42 <-> 29 +43 <-> 30 +44 <-> 31 +45 <-> 32 +49 <-> 35 +50 <-> 36 +51 <-> 37 +52 <-> 38 +53 <-> 39 +55 <-> 42 +56 <-> 43 +57 <-> 44 +58 <-> 45 +59 <-> 46 +61 <-> 49 +62 <-> 50 +63 <-> 51 +64 <-> 52 +65 <-> 53 +67 <-> 56 +68 <-> 57 +69 <-> 58 +70 <-> 59 +71 <-> 60 +73 <-> 63 diff --git a/testData/results/pkg/TestPPMMOnStaticField.dec b/testData/results/pkg/TestPPMMOnStaticField.dec new file mode 100644 index 0000000000..4a371a42ae --- /dev/null +++ b/testData/results/pkg/TestPPMMOnStaticField.dec @@ -0,0 +1,321 @@ +package pkg; + +public class TestPPMMOnStaticField { + static int a; + + public void ipp() { + ++a;// 23 + ++a;// 24 + ++a;// 25 + ++a;// 26 + }// 27 + + public void ppi() { + ++a;// 29 + ++a;// 30 + ++a;// 31 + ++a;// 32 + }// 33 + + public void imm() { + --a;// 35 + --a;// 36 + --a;// 37 + --a;// 38 + }// 39 + + public void mmi() { + --a;// 41 + --a;// 42 + --a;// 43 + --a;// 44 + }// 45 + + public void ippf() { + t(a++);// 49 + t(a++);// 50 + t(a++);// 51 + t(a++);// 52 + }// 53 + + public void ppif() { + t(++a);// 55 + t(++a);// 56 + t(++a);// 57 + t(++a);// 58 + }// 59 + + public void immf() { + t(a--);// 61 + t(a--);// 62 + t(a--);// 63 + t(a--);// 64 + }// 65 + + public void mmif() { + t(--a);// 67 + t(--a);// 68 + t(--a);// 69 + t(--a);// 70 + }// 71 + + private static void t(int x) { + }// 73 +} + +class 'pkg/TestPPMMOnStaticField' { + method 'ipp ()V' { + 0 6 + 1 6 + 2 6 + 4 6 + 8 7 + 9 7 + a 7 + c 7 + 10 8 + 11 8 + 12 8 + 14 8 + 18 9 + 19 9 + 1a 9 + 1c 9 + 20 10 + } + + method 'ppi ()V' { + 0 13 + 1 13 + 2 13 + 4 13 + 8 14 + 9 14 + a 14 + c 14 + 10 15 + 11 15 + 12 15 + 14 15 + 18 16 + 19 16 + 1a 16 + 1c 16 + 20 17 + } + + method 'imm ()V' { + 0 20 + 1 20 + 2 20 + 4 20 + 8 21 + 9 21 + a 21 + c 21 + 10 22 + 11 22 + 12 22 + 14 22 + 18 23 + 19 23 + 1a 23 + 1c 23 + 20 24 + } + + method 'mmi ()V' { + 0 27 + 1 27 + 2 27 + 4 27 + 8 28 + 9 28 + a 28 + c 28 + 10 29 + 11 29 + 12 29 + 14 29 + 18 30 + 19 30 + 1a 30 + 1c 30 + 20 31 + } + + method 'ippf ()V' { + 0 34 + 1 34 + 2 34 + 5 34 + 9 34 + a 34 + b 34 + c 35 + d 35 + e 35 + 11 35 + 15 35 + 16 35 + 17 35 + 18 36 + 19 36 + 1a 36 + 1d 36 + 21 36 + 22 36 + 23 36 + 24 37 + 25 37 + 26 37 + 29 37 + 2d 37 + 2e 37 + 2f 37 + 30 38 + } + + method 'ppif ()V' { + 0 41 + 1 41 + 2 41 + 4 41 + 9 41 + a 41 + b 41 + c 42 + d 42 + e 42 + 10 42 + 15 42 + 16 42 + 17 42 + 18 43 + 19 43 + 1a 43 + 1c 43 + 21 43 + 22 43 + 23 43 + 24 44 + 25 44 + 26 44 + 28 44 + 2d 44 + 2e 44 + 2f 44 + 30 45 + } + + method 'immf ()V' { + 0 48 + 1 48 + 2 48 + 5 48 + 9 48 + a 48 + b 48 + c 49 + d 49 + e 49 + 11 49 + 15 49 + 16 49 + 17 49 + 18 50 + 19 50 + 1a 50 + 1d 50 + 21 50 + 22 50 + 23 50 + 24 51 + 25 51 + 26 51 + 29 51 + 2d 51 + 2e 51 + 2f 51 + 30 52 + } + + method 'mmif ()V' { + 0 55 + 1 55 + 2 55 + 4 55 + 9 55 + a 55 + b 55 + c 56 + d 56 + e 56 + 10 56 + 15 56 + 16 56 + 17 56 + 18 57 + 19 57 + 1a 57 + 1c 57 + 21 57 + 22 57 + 23 57 + 24 58 + 25 58 + 26 58 + 28 58 + 2d 58 + 2e 58 + 2f 58 + 30 59 + } + + method 't (I)V' { + 0 62 + } +} + +Lines mapping: +23 <-> 7 +24 <-> 8 +25 <-> 9 +26 <-> 10 +27 <-> 11 +29 <-> 14 +30 <-> 15 +31 <-> 16 +32 <-> 17 +33 <-> 18 +35 <-> 21 +36 <-> 22 +37 <-> 23 +38 <-> 24 +39 <-> 25 +41 <-> 28 +42 <-> 29 +43 <-> 30 +44 <-> 31 +45 <-> 32 +49 <-> 35 +50 <-> 36 +51 <-> 37 +52 <-> 38 +53 <-> 39 +55 <-> 42 +56 <-> 43 +57 <-> 44 +58 <-> 45 +59 <-> 46 +61 <-> 49 +62 <-> 50 +63 <-> 51 +64 <-> 52 +65 <-> 53 +67 <-> 56 +68 <-> 57 +69 <-> 58 +70 <-> 59 +71 <-> 60 +73 <-> 63 diff --git a/testData/src/java8/pkg/TestPPMMBoxed.java b/testData/src/java8/pkg/TestPPMMBoxed.java new file mode 100644 index 0000000000..7e5a84ee29 --- /dev/null +++ b/testData/src/java8/pkg/TestPPMMBoxed.java @@ -0,0 +1,81 @@ +/* + * 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 TestPPMMBoxed { + // Bytecode wise ipp and ppi are identical when not using the intermediate value. + // We keep these seperate tests just to see the bytecode. + public void ipp() { + Integer a = 0; + a++; + a++; + a++; + a++; + } + public void ppi() { + Integer a = 0; + ++a; + ++a; + ++a; + ++a; + } + public void imm() { + Integer a = 0; + a--; + a--; + a--; + a--; + } + public void mmi() { + Integer a = 0; + --a; + --a; + --a; + --a; + } + + // These versions actually use the intermediate value + public void ippf() { + Integer a = 0; + t(a++); + t(a++); + t(a++); + t(a++); + } + public void ppif() { + Integer a = 0; + t(++a); + t(++a); + t(++a); + t(++a); + } + public void immf() { + Integer a = 0; + t(a--); + t(a--); + t(a--); + t(a--); + } + public void mmif() { + Integer a = 0; + t(--a); + t(--a); + t(--a); + t(--a); + } + private static void t(int x){ + } +} \ No newline at end of file diff --git a/testData/src/java8/pkg/TestPPMMByte.java b/testData/src/java8/pkg/TestPPMMByte.java new file mode 100644 index 0000000000..9ce2fe5273 --- /dev/null +++ b/testData/src/java8/pkg/TestPPMMByte.java @@ -0,0 +1,81 @@ +/* + * 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 TestPPMMByte { + // Bytecode wise ipp and ppi are identical when not using the intermediate value. + // We keep these seperate tests just to see the bytecode. + public void ipp() { + byte a = 0; + a++; + a++; + a++; + a++; + } + public void ppi() { + byte a = 0; + ++a; + ++a; + ++a; + ++a; + } + public void imm() { + byte a = 0; + a--; + a--; + a--; + a--; + } + public void mmi() { + byte a = 0; + --a; + --a; + --a; + --a; + } + + // These versions actually use the intermediate value + public void ippf() { + byte a = 0; + t(a++); + t(a++); + t(a++); + t(a++); + } + public void ppif() { + byte a = 0; + t(++a); + t(++a); + t(++a); + t(++a); + } + public void immf() { + byte a = 0; + t(a--); + t(a--); + t(a--); + t(a--); + } + public void mmif() { + byte a = 0; + t(--a); + t(--a); + t(--a); + t(--a); + } + private static void t(byte x){ + } +} \ No newline at end of file diff --git a/testData/src/java8/pkg/TestPPMMLong.java b/testData/src/java8/pkg/TestPPMMLong.java new file mode 100644 index 0000000000..70ef50d6fd --- /dev/null +++ b/testData/src/java8/pkg/TestPPMMLong.java @@ -0,0 +1,81 @@ +/* + * 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 TestPPMMLong { + // Bytecode wise ipp and ppi are identical when not using the intermediate value. + // We keep these seperate tests just to see the bytecode. + public void ipp() { + long a = 0; + a++; + a++; + a++; + a++; + } + public void ppi() { + long a = 0; + ++a; + ++a; + ++a; + ++a; + } + public void imm() { + long a = 0; + a--; + a--; + a--; + a--; + } + public void mmi() { + long a = 0; + --a; + --a; + --a; + --a; + } + + // These versions actually use the intermediate value + public void ippf() { + long a = 0; + t(a++); + t(a++); + t(a++); + t(a++); + } + public void ppif() { + long a = 0; + t(++a); + t(++a); + t(++a); + t(++a); + } + public void immf() { + long a = 0; + t(a--); + t(a--); + t(a--); + t(a--); + } + public void mmif() { + long a = 0; + t(--a); + t(--a); + t(--a); + t(--a); + } + private static void t(long x){ + } +} \ No newline at end of file diff --git a/testData/src/java8/pkg/TestPPMMOnObjectField.java b/testData/src/java8/pkg/TestPPMMOnObjectField.java new file mode 100644 index 0000000000..4a053eeef1 --- /dev/null +++ b/testData/src/java8/pkg/TestPPMMOnObjectField.java @@ -0,0 +1,74 @@ +/* + * 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 TestPPMMOnObjectField { + int a; + // Bytecode wise ipp and ppi are identical when not using the intermediate value. + // We keep these seperate tests just to see the bytecode. + public void ipp() { + a++; + a++; + a++; + a++; + } + public void ppi() { + ++a; + ++a; + ++a; + ++a; + } + public void imm() { + a--; + a--; + a--; + a--; + } + public void mmi() { + --a; + --a; + --a; + --a; + } + + // These versions actually use the intermediate value + public void ippf() { + t(a++); + t(a++); + t(a++); + t(a++); + } + public void ppif() { + t(++a); + t(++a); + t(++a); + t(++a); + } + public void immf() { + t(a--); + t(a--); + t(a--); + t(a--); + } + public void mmif() { + t(--a); + t(--a); + t(--a); + t(--a); + } + private static void t(int x){ + } +} \ No newline at end of file diff --git a/testData/src/java8/pkg/TestPPMMOnStaticField.java b/testData/src/java8/pkg/TestPPMMOnStaticField.java new file mode 100644 index 0000000000..32cff6010e --- /dev/null +++ b/testData/src/java8/pkg/TestPPMMOnStaticField.java @@ -0,0 +1,74 @@ +/* + * 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 TestPPMMOnStaticField { + static int a; + // Bytecode wise ipp and ppi are identical when not using the intermediate value. + // We keep these seperate tests just to see the bytecode. + public void ipp() { + a++; + a++; + a++; + a++; + } + public void ppi() { + ++a; + ++a; + ++a; + ++a; + } + public void imm() { + a--; + a--; + a--; + a--; + } + public void mmi() { + --a; + --a; + --a; + --a; + } + + // These versions actually use the intermediate value + public void ippf() { + t(a++); + t(a++); + t(a++); + t(a++); + } + public void ppif() { + t(++a); + t(++a); + t(++a); + t(++a); + } + public void immf() { + t(a--); + t(a--); + t(a--); + t(a--); + } + public void mmif() { + t(--a); + t(--a); + t(--a); + t(--a); + } + private static void t(int x){ + } +} \ No newline at end of file From 76d6049889e812bdb77f2f34fb0bad77df1041d0 Mon Sep 17 00:00:00 2001 From: Joseph Burton Date: Sun, 14 Nov 2021 19:31:17 +0000 Subject: [PATCH 07/85] Replace bytecode mappings with text buffer (#53) --- .../java/decompiler/main/ClassWriter.java | 135 +++------ .../decompiler/main/ClassesProcessor.java | 14 +- .../java/decompiler/main/RecordHelper.java | 7 +- .../modules/decompiler/ExprProcessor.java | 30 +- .../decompiler/exps/AnnotationExprent.java | 5 +- .../modules/decompiler/exps/ArrayExprent.java | 10 +- .../decompiler/exps/AssertExprent.java | 9 +- .../decompiler/exps/AssignmentExprent.java | 8 +- .../modules/decompiler/exps/ConstExprent.java | 159 +++++----- .../modules/decompiler/exps/ExitExprent.java | 23 +- .../modules/decompiler/exps/Exprent.java | 9 +- .../modules/decompiler/exps/FieldExprent.java | 13 +- .../decompiler/exps/FunctionExprent.java | 90 +++--- .../modules/decompiler/exps/IfExprent.java | 10 +- .../decompiler/exps/InvocationExprent.java | 22 +- .../decompiler/exps/MonitorExprent.java | 11 +- .../modules/decompiler/exps/NewExprent.java | 34 +-- .../decompiler/exps/SwitchExprent.java | 8 +- .../modules/decompiler/exps/VarExprent.java | 11 +- .../decompiler/stats/BasicBlockStatement.java | 7 +- .../decompiler/stats/CatchAllStatement.java | 29 +- .../decompiler/stats/CatchStatement.java | 23 +- .../modules/decompiler/stats/DoStatement.java | 38 +-- .../decompiler/stats/GeneralStatement.java | 5 +- .../modules/decompiler/stats/IfStatement.java | 30 +- .../decompiler/stats/RootStatement.java | 5 +- .../decompiler/stats/SequenceStatement.java | 10 +- .../modules/decompiler/stats/Statement.java | 4 +- .../decompiler/stats/SwitchStatement.java | 17 +- .../stats/SynchronizedStatement.java | 29 +- .../java/decompiler/util/DebugPrinter.java | 5 +- .../jetbrains/java/decompiler/util/Pair.java | 36 +++ .../java/decompiler/util/TextBuffer.java | 99 +++++- testData/results/pkg/TestAnonymousClass.dec | 20 +- testData/results/pkg/TestAnonymousParams.dec | 18 +- .../results/pkg/TestAnonymousSignature.dec | 32 +- testData/results/pkg/TestClassLambda.dec | 183 +++++------ .../pkg/TestClassNestedInitializer.dec | 30 +- .../pkg/TestClassSimpleBytecodeMapping.dec | 28 +- .../pkg/TestDoubleBraceInitializers.dec | 48 +-- .../results/pkg/TestDoubleNestedClass.dec | 26 +- testData/results/pkg/TestDuplicateLocals.dec | 286 +++++++++--------- testData/results/pkg/TestInfiniteLoop.dec | 5 - testData/results/pkg/TestLambdaParams.dec | 38 +-- testData/results/pkg/TestLocalClass.dec | 32 +- testData/results/pkg/TestLocalRecord.dec | 14 +- .../pkg/TestMethodReferenceSameName.dec | 4 + testData/results/pkg/TestNestedLambdas.dec | 62 ++-- testData/results/pkg/TestObjectArrays.dec | 102 +++---- .../pkg/TestPatternMatchingLocalCapture.dec | 24 +- testData/results/pkg/TestPrivateClasses.dec | 254 ++++++++-------- testData/results/pkg/TestThrowException.dec | 16 +- testData/results/pkg/TestTryLoop.dec | 9 - .../pkg/TestTryWithResourcesReturnJ16.dec | 7 - testData/results/pkg/TestUnionType.dec | 16 +- testData/results/pkg/TestWhileTernary10.dec | 76 ++--- 56 files changed, 1131 insertions(+), 1144 deletions(-) create mode 100644 src/org/jetbrains/java/decompiler/util/Pair.java diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 6e04581278..6ee438f77b 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -6,7 +6,6 @@ import org.jetbrains.java.decompiler.code.Instruction; import org.jetbrains.java.decompiler.code.InstructionSequence; import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.main.rels.ClassWrapper; @@ -34,8 +33,6 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection; import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.*; import java.util.stream.Collectors; @@ -79,7 +76,7 @@ private static void invokeProcessors(ClassNode node) { } } - public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_object, int indent, BytecodeMappingTracer origTracer) { + public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_object, int indent) { ClassWrapper wrapper = node.getWrapper(); if (wrapper == null) { return; @@ -90,8 +87,6 @@ public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_ ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node); - BytecodeMappingTracer tracer = new BytecodeMappingTracer(origTracer.getCurrentSourceLine()); - try { StructClass cl = wrapper.getClassStruct(); @@ -101,7 +96,7 @@ public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_ if (!node.lambdaInformation.is_content_method_static && method_object != null) { // reference to a virtual method method_object.getInferredExprType(new VarType(CodeConstants.TYPE_OBJECT, 0, node.lambdaInformation.content_class_name)); - String instance = method_object.toJava(indent, tracer).toString(); + TextBuffer instance = method_object.toJava(indent); // If the instance is casted, then we need to wrap it if (method_object.type == Exprent.EXPRENT_FUNCTION && ((FunctionExprent)method_object).getFuncType() == FunctionExprent.FUNCTION_CAST && ((FunctionExprent)method_object).doesCast()) { buffer.append('(').append(instance).append(')'); @@ -175,14 +170,15 @@ public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_ MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper); try { - TextBuffer codeBuffer = firstExpr.toJava(indent + 1, tracer); + TextBuffer codeBuffer = firstExpr.toJava(indent + 1); if (firstExpr.type == Exprent.EXPRENT_EXIT) codeBuffer.setStart(6); // skip return else codeBuffer.prepend(" "); - buffer.append(codeBuffer); + codeBuffer.addBytecodeMapping(root.getDummyExit().bytecode); + buffer.append(codeBuffer, node.classStruct.qualifiedName, InterpreterUtil.makeUniqueKey(methodWrapper.methodStruct.getName(), methodWrapper.methodStruct.getDescriptor())); } catch (Throwable ex) { DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " in class " + node.classStruct.qualifiedName + " couldn't be written.", @@ -192,8 +188,6 @@ public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_ buffer.append(" // $FF: Couldn't be decompiled"); } finally { - tracer.addMapping(root.getDummyExit().bytecode); - addTracer(cl, mt, tracer); DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper); } } @@ -203,13 +197,10 @@ public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_ if (!simpleLambda) { buffer.append(" {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - methodLambdaToJava(node, wrapper, mt, buffer, indent + 1, !lambdaToAnonymous, tracer); + methodLambdaToJava(node, wrapper, mt, buffer, indent + 1, !lambdaToAnonymous); buffer.appendIndent(indent).append("}"); - - addTracer(cl, mt, tracer); } } } @@ -220,13 +211,10 @@ public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_ DecompilerContext.getLogger().endWriteClass(); } - public void classToJava(ClassNode node, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) { + public void classToJava(ClassNode node, TextBuffer buffer, int indent) { ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node); - int startLine = tracer != null ? tracer.getCurrentSourceLine() : 0; - BytecodeMappingTracer dummy_tracer = new BytecodeMappingTracer(startLine); - try { // last minute processing invokeProcessors(node); @@ -237,16 +225,15 @@ public void classToJava(ClassNode node, TextBuffer buffer, int indent, BytecodeM DecompilerContext.getLogger().startWriteClass(cl.qualifiedName); // write class definition - int start_class_def = buffer.length(); writeClassDefinition(node, buffer, indent); boolean hasContent = false; boolean enumFields = false; - dummy_tracer.incrementCurrentSourceLine(buffer.countLines(start_class_def)); - List components = cl.getRecordComponents(); + // FIXME: fields don't have line mappings + // fields for (StructField fd : cl.getFields()) { boolean hide = fd.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) || wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); @@ -262,7 +249,6 @@ public void classToJava(ClassNode node, TextBuffer buffer, int indent, BytecodeM if (isEnum) { if (enumFields) { buffer.append(',').appendLineSeparator(); - dummy_tracer.incrementCurrentSourceLine(); } enumFields = true; } @@ -270,23 +256,21 @@ else if (enumFields) { buffer.append(';'); buffer.appendLineSeparator(); buffer.appendLineSeparator(); - dummy_tracer.incrementCurrentSourceLine(2); enumFields = false; } - fieldToJava(wrapper, cl, fd, buffer, indent + 1, dummy_tracer); // FIXME: insert real tracer + TextBuffer fieldBuffer = new TextBuffer(); + fieldToJava(wrapper, cl, fd, fieldBuffer, indent + 1); + fieldBuffer.clearUnassignedBytecodeMappingData(); + buffer.append(fieldBuffer); hasContent = true; } if (enumFields) { buffer.append(';').appendLineSeparator(); - dummy_tracer.incrementCurrentSourceLine(); } - // FIXME: fields don't matter at the moment - startLine += buffer.countLines(start_class_def); - // methods VBStyleCollection methods = cl.getMethods(); for (int i = 0; i < methods.size(); i++) { @@ -296,22 +280,14 @@ else if (enumFields) { wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor())); if (hide) continue; - int position = buffer.length(); - int storedLine = startLine; - if (hasContent) { - buffer.appendLineSeparator(); - startLine++; - } - BytecodeMappingTracer method_tracer = new BytecodeMappingTracer(startLine); - boolean methodSkipped = !methodToJava(node, mt, i, buffer, indent + 1, method_tracer); + TextBuffer methodBuffer = new TextBuffer(); + boolean methodSkipped = !methodToJava(node, mt, i, methodBuffer, indent + 1); if (!methodSkipped) { + if (hasContent) { + buffer.appendLineSeparator(); + } hasContent = true; - addTracer(cl, mt, method_tracer); - startLine = method_tracer.getCurrentSourceLine(); - } - else { - buffer.setLength(position); - startLine = storedLine; + buffer.append(methodBuffer); } } @@ -326,11 +302,8 @@ else if (enumFields) { if (hasContent) { buffer.appendLineSeparator(); - startLine++; } - BytecodeMappingTracer class_tracer = new BytecodeMappingTracer(startLine); - classToJava(inner, buffer, indent + 1, class_tracer); - startLine = buffer.countLines(); + classToJava(inner, buffer, indent + 1); hasContent = true; } @@ -443,13 +416,6 @@ private static void writeModuleInfoBody(TextBuffer buffer, StructModuleAttribute private static boolean isGenerated(int flags) { return (flags & (CodeConstants.ACC_SYNTHETIC | CodeConstants.ACC_MANDATED)) != 0; } - - private static void addTracer(StructClass cls, StructMethod method, BytecodeMappingTracer tracer) { - StructLineNumberTableAttribute table = method.getAttribute(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); - tracer.setLineNumberTable(table); - String key = InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor()); - DecompilerContext.getBytecodeSourceMapper().addTracer(cls.qualifiedName, key, tracer); - } private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) { if (node.type == ClassNode.CLASS_ANONYMOUS) { @@ -611,8 +577,7 @@ private static boolean isSuperClassSealed(StructClass cl) { return false; } - private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) { - int start = buffer.length(); + private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, TextBuffer buffer, int indent) { boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE); boolean isDeprecated = fd.hasAttribute(StructGeneralAttribute.ATTRIBUTE_DEPRECATED); boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); @@ -652,8 +617,6 @@ private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, T buffer.append(fd.getName()); - tracer.incrementCurrentSourceLine(buffer.countLines(start)); - Exprent initializer; if (fd.hasModifier(CodeConstants.ACC_STATIC)) { initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); @@ -665,7 +628,7 @@ private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, T if (isEnum && initializer.type == Exprent.EXPRENT_NEW) { NewExprent expr = (NewExprent)initializer; expr.setEnumConst(true); - buffer.append(expr.toJava(indent, tracer)); + buffer.append(expr.toJava(indent)); } else { buffer.append(" = "); @@ -675,7 +638,7 @@ private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, T } // 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); + ExprProcessor.getCastedExprent(initializer, descriptor == null ? fieldType : descriptor.type, buffer, indent, false); } } else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) { @@ -683,13 +646,12 @@ else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants if (attr != null) { PrimitiveConstant constant = cl.getPool().getPrimitiveConstant(attr.getIndex()); buffer.append(" = "); - buffer.append(new ConstExprent(fieldType, constant.value, null).toJava(indent, tracer)); + buffer.append(new ConstExprent(fieldType, constant.value, null).toJava(indent)); } } if (!isEnum) { buffer.append(";").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } } @@ -698,7 +660,7 @@ private static void methodLambdaToJava(ClassNode lambdaNode, StructMethod mt, TextBuffer buffer, int indent, - boolean codeOnly, BytecodeMappingTracer tracer) { + boolean codeOnly) { MethodWrapper methodWrapper = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()); MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); @@ -752,7 +714,9 @@ private static void methodLambdaToJava(ClassNode lambdaNode, if (methodWrapper.decompileError == null) { if (root != null) { // check for existence try { - buffer.append(root.toJava(indent, tracer)); + TextBuffer childBuf = root.toJava(indent); + childBuf.addBytecodeMapping(root.getDummyExit().bytecode); + buffer.append(childBuf, classWrapper.getClassStruct().qualifiedName, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor())); } catch (Throwable t) { String message = "Method " + mt.getName() + " " + mt.getDescriptor() + " in class " + lambdaNode.classStruct.qualifiedName + " couldn't be written."; @@ -763,11 +727,7 @@ private static void methodLambdaToJava(ClassNode lambdaNode, } if (methodWrapper.decompileError != null) { - dumpError(buffer, methodWrapper, indent, tracer); - } - - if (root != null) { - tracer.addMapping(root.getDummyExit().bytecode); + dumpError(buffer, methodWrapper, indent); } if (!codeOnly) { @@ -802,14 +762,13 @@ private static String toValidJavaIdentifier(String name) { return res.append("/* $FF was: ").append(name).append("*/").toString(); } - private boolean methodToJava(ClassNode node, StructMethod mt, int methodIndex, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) { + private boolean methodToJava(ClassNode node, StructMethod mt, int methodIndex, TextBuffer buffer, int indent) { ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); // Get method by index, this keeps duplicate methods (with the same key) separate MethodWrapper methodWrapper = wrapper.getMethodWrapper(methodIndex); boolean hideMethod = false; - int start_index_method = buffer.length(); MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper); @@ -1011,14 +970,12 @@ else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarT } } - tracer.incrementCurrentSourceLine(buffer.countLines(start_index_method)); - if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) { // native or abstract method (explicit or interface) if (isAnnotation) { StructAnnDefaultAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_ANNOTATION_DEFAULT); if (attr != null) { buffer.append(" default "); - buffer.append(attr.getDefaultValue().toJava(0, BytecodeMappingTracer.DUMMY)); + buffer.append(attr.getDefaultValue().toJava(0)); } } @@ -1032,28 +989,20 @@ else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarT // We do not have line information for method start, lets have it here for now buffer.append('{').appendLineSeparator(); - tracer.incrementCurrentSourceLine(); RootStatement root = methodWrapper.root; if (root != null && methodWrapper.decompileError == null) { // check for existence try { - // to restore in case of an exception - BytecodeMappingTracer codeTracer = new BytecodeMappingTracer(tracer.getCurrentSourceLine()); - // Avoid generating imports for ObjectMethods during root.toJava(...) if (RecordHelper.isHiddenRecordMethod(cl, mt, root)) { hideMethod = true; } else { - TextBuffer code = root.toJava(indent + 1, codeTracer); - + TextBuffer code = root.toJava(indent + 1); + code.addBytecodeMapping(root.getDummyExit().bytecode); hideMethod = code.length() == 0 && (clInit || dInit || hideConstructor(node, init, throwsExceptions, paramCount, flags)); - buffer.append(code); + buffer.append(code, cl.qualifiedName, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor())); } - - - tracer.setCurrentSourceLine(codeTracer.getCurrentSourceLine()); - tracer.addTracer(codeTracer); } catch (Throwable t) { String message = "Method " + mt.getName() + " " + mt.getDescriptor() + " in class " + node.classStruct.qualifiedName + " couldn't be written."; @@ -1063,15 +1012,10 @@ else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarT } if (methodWrapper.decompileError != null) { - dumpError(buffer, methodWrapper, indent + 1, tracer); - } - else if (root != null) { - tracer.addMapping(root.getDummyExit().bytecode); + dumpError(buffer, methodWrapper, indent + 1); } buffer.appendIndent(indent).append('}').appendLineSeparator(); } - - tracer.incrementCurrentSourceLine(); } finally { DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper); @@ -1084,7 +1028,7 @@ else if (root != null) { return !hideMethod; } - private static void dumpError(TextBuffer buffer, MethodWrapper wrapper, int indent, BytecodeMappingTracer tracer) { + private static void dumpError(TextBuffer buffer, MethodWrapper wrapper, int indent) { List lines = new ArrayList<>(); lines.add("$FF: Couldn't be decompiled"); boolean exceptions = DecompilerContext.getOption(IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR); @@ -1111,7 +1055,6 @@ private static void dumpError(TextBuffer buffer, MethodWrapper wrapper, int inde buffer.append("//"); if (!line.isEmpty()) buffer.append(' ').append(line); buffer.appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } } @@ -1386,7 +1329,7 @@ static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, in StructAnnotationAttribute attribute = (StructAnnotationAttribute)mb.getAttribute(key); if (attribute != null) { for (AnnotationExprent annotation : attribute.getAnnotations()) { - String text = annotation.toJava(indent, BytecodeMappingTracer.DUMMY).toString(); + String text = annotation.toJava(indent).toString(); filter.add(text); buffer.append(text); if (indent < 0) { @@ -1457,7 +1400,7 @@ private static void appendParameterAnnotations(TextBuffer buffer, StructMethod m List> annotations = attribute.getParamAnnotations(); if (param < annotations.size()) { for (AnnotationExprent annotation : annotations.get(param)) { - String text = annotation.toJava(-1, BytecodeMappingTracer.DUMMY).toString(); + String text = annotation.toJava(-1).toString(); filter.add(text); buffer.append(text).append(' '); } @@ -1474,7 +1417,7 @@ private static void appendTypeAnnotations(TextBuffer buffer, int indent, StructM if (attribute != null) { for (TypeAnnotation annotation : attribute.getAnnotations()) { if (annotation.isTopLevel() && annotation.getTargetType() == targetType && (index < 0 || annotation.getIndex() == index)) { - String text = annotation.getAnnotation().toJava(indent, BytecodeMappingTracer.DUMMY).toString(); + String text = annotation.getAnnotation().toJava(indent).toString(); if (!filter.contains(text)) { buffer.append(text); if (indent < 0) { diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index 6e775ce6c6..07d1dc0b05 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -1,7 +1,6 @@ // 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.main; -import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.code.Instruction; import org.jetbrains.java.decompiler.code.InstructionSequence; @@ -12,7 +11,6 @@ import org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer; import org.jetbrains.java.decompiler.main.rels.ClassWrapper; import org.jetbrains.java.decompiler.main.rels.LambdaProcessor; -import org.jetbrains.java.decompiler.main.rels.MethodWrapper; import org.jetbrains.java.decompiler.main.rels.NestedClassProcessor; import org.jetbrains.java.decompiler.main.rels.NestedMemberAccess; import org.jetbrains.java.decompiler.modules.decompiler.SwitchHelper; @@ -24,6 +22,7 @@ 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.StructLineNumberTableAttribute; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; @@ -442,7 +441,16 @@ else if (moduleInfo) { new NestedMemberAccess().propagateMemberAccess(root); TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE); - new ClassWriter().classToJava(root, classBuffer, 0, null); + new ClassWriter().classToJava(root, classBuffer, 0); + classBuffer.getTracers().forEach((classAndMethod, tracer) -> { + // get the class by name + StructClass clazz = DecompilerContext.getStructContext().getClass(classAndMethod.a); + StructMethod method = clazz.getMethod(classAndMethod.b); + StructLineNumberTableAttribute lineNumberTable = + method.getAttribute(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); + tracer.setLineNumberTable(lineNumberTable); + DecompilerContext.getBytecodeSourceMapper().addTracer(classAndMethod.a, classAndMethod.b, tracer); + }); int index = cl.qualifiedName.lastIndexOf('/'); if (index >= 0) { diff --git a/src/org/jetbrains/java/decompiler/main/RecordHelper.java b/src/org/jetbrains/java/decompiler/main/RecordHelper.java index be816ba6cb..8867781f91 100644 --- a/src/org/jetbrains/java/decompiler/main/RecordHelper.java +++ b/src/org/jetbrains/java/decompiler/main/RecordHelper.java @@ -1,7 +1,6 @@ package org.jetbrains.java.decompiler.main; import org.jetbrains.java.decompiler.code.CodeConstants; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement; @@ -126,7 +125,7 @@ private static Set getRecordComponentAnnotations(StructClass cl, StructR StructAnnotationAttribute attribute = (StructAnnotationAttribute) member.getAttribute(key); if (attribute == null) continue; for (AnnotationExprent annotation : attribute.getAnnotations()) { - String text = annotation.toJava(-1, BytecodeMappingTracer.DUMMY).toString(); + String text = annotation.toJava(-1).toString(); annotations.add(text); } } @@ -138,7 +137,7 @@ private static Set getRecordComponentAnnotations(StructClass cl, StructR if (!annotation.isTopLevel()) continue; int type = annotation.getTargetType(); if (type == TypeAnnotation.FIELD || type == TypeAnnotation.METHOD_PARAMETER) { - String text = annotation.getAnnotation().toJava(-1, BytecodeMappingTracer.DUMMY).toString(); + String text = annotation.getAnnotation().toJava(-1).toString(); annotations.add(text); } } @@ -154,7 +153,7 @@ private static Set getRecordComponentAnnotations(StructClass cl, StructR List> paramAnnotations = attribute.getParamAnnotations(); if (param >= paramAnnotations.size()) continue; for (AnnotationExprent annotation : paramAnnotations.get(param)) { - String text = annotation.toJava(-1, BytecodeMappingTracer.DUMMY).toString(); + String text = annotation.toJava(-1).toString(); annotations.add(text); } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java index 9f0a721294..a172b5b8b1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java @@ -781,19 +781,19 @@ public static boolean endsWithSemicolon(Exprent expr) { (type == Exprent.EXPRENT_VAR && ((VarExprent)expr).isClassDef())); } - private static void addDeletedGotoInstructionMapping(Statement stat, BytecodeMappingTracer tracer) { + private static void addDeletedGotoInstructionMapping(Statement stat, TextBuffer buffer) { if (stat instanceof BasicBlockStatement) { BasicBlock block = ((BasicBlockStatement)stat).getBlock(); List offsets = block.getInstrOldOffsets(); if (!offsets.isEmpty() && offsets.size() > block.getSeq().length()) { // some instructions have been deleted, but we still have offsets - tracer.addMapping(offsets.get(offsets.size() - 1)); // add the last offset + buffer.addBytecodeMapping(offsets.get(offsets.size() - 1)); // add the last offset } } } - public static TextBuffer jmpWrapper(Statement stat, int indent, boolean semicolon, BytecodeMappingTracer tracer) { - TextBuffer buf = stat.toJava(indent, tracer); + public static TextBuffer jmpWrapper(Statement stat, int indent, boolean semicolon) { + TextBuffer buf = stat.toJava(indent); List lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL); if (lstSuccs.size() == 1) { @@ -803,11 +803,11 @@ public static TextBuffer jmpWrapper(Statement stat, int indent, boolean semicolo switch (edge.getType()) { case StatEdge.TYPE_BREAK: - addDeletedGotoInstructionMapping(stat, tracer); + addDeletedGotoInstructionMapping(stat, buf); buf.append("break"); break; case StatEdge.TYPE_CONTINUE: - addDeletedGotoInstructionMapping(stat, tracer); + addDeletedGotoInstructionMapping(stat, buf); buf.append("continue"); } @@ -815,13 +815,11 @@ public static TextBuffer jmpWrapper(Statement stat, int indent, boolean semicolo buf.append(" label").append(edge.closure.id.toString()); } buf.append(";").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } } if (buf.length() == 0 && semicolon) { buf.appendIndent(indent).append(";").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } return buf; @@ -841,7 +839,7 @@ public static String buildJavaClassName(String name) { return res; } - public static TextBuffer listToJava(List lst, int indent, BytecodeMappingTracer tracer) { + public static TextBuffer listToJava(List lst, int indent) { if (lst == null || lst.isEmpty()) { return new TextBuffer(); } @@ -853,12 +851,11 @@ public static TextBuffer listToJava(List lst, int indent, Byt if (buf.length() > 0 && expr.type == Exprent.EXPRENT_VAR && ((VarExprent)expr).isClassDef()) { // separates local class definition from previous statements buf.appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } expr.getInferredExprType(null); - TextBuffer content = expr.toJava(indent, tracer); + TextBuffer content = expr.toJava(indent); if (content.length() > 0) { if (expr.type != Exprent.EXPRENT_VAR || !((VarExprent)expr).isClassDef()) { @@ -872,7 +869,6 @@ public static TextBuffer listToJava(List lst, int indent, Byt buf.append(";"); } buf.appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } } @@ -903,9 +899,8 @@ public static boolean getCastedExprent(Exprent exprent, VarType leftType, TextBuffer buffer, int indent, - boolean castNull, - BytecodeMappingTracer tracer) { - return getCastedExprent(exprent, leftType, buffer, indent, castNull, false, false, false, tracer); + boolean castNull) { + return getCastedExprent(exprent, leftType, buffer, indent, castNull, false, false, false); } public static boolean getCastedExprent(Exprent exprent, @@ -915,8 +910,7 @@ public static boolean getCastedExprent(Exprent exprent, boolean castNull, boolean castAlways, boolean castNarrowing, - boolean unbox, - BytecodeMappingTracer tracer) { + boolean unbox) { if (unbox) { // "unbox" invocation parameters, e.g. 'byteSet.add((byte)123)' or 'new ShortContainer((short)813)' @@ -965,7 +959,7 @@ else if (leftType.equals(VarType.VARTYPE_SHORT_OBJ)) { ((ConstExprent) exprent).adjustConstType(leftType); } - buffer.append(exprent.toJava(indent, tracer)); + buffer.append(exprent.toJava(indent)); if (quote) buffer.append(')'); 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 df0898d64a..8b98737029 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java @@ -4,7 +4,6 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; 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.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.TextBuffer; @@ -36,7 +35,7 @@ protected List getAllExprents(List list) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buffer = new TextBuffer(); buffer.appendIndent(indent); @@ -60,7 +59,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { buffer.append(" = "); } - buffer.append(parValues.get(i).toJava(0, tracer)); + buffer.append(parValues.get(i).toJava(0)); if (i < parNames.size() - 1) { buffer.append(','); 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 ecdbdc6dfc..26d3e71f65 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java @@ -1,14 +1,12 @@ // Copyright 2000-2018 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.exps; -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.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.TextBuffer; -import java.util.ArrayList; import java.util.BitSet; import java.util.List; @@ -74,8 +72,8 @@ public List getAllExprents(List lst) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - TextBuffer res = array.toJava(indent, tracer); + public TextBuffer toJava(int indent) { + TextBuffer res = array.toJava(indent); if (array.getPrecedence() > getPrecedence()) { // array precedence equals 0 res.enclose("(", ")"); @@ -87,9 +85,9 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { res.enclose("((" + ExprProcessor.getCastTypeName(objArr) + ")", ")"); } - tracer.addMapping(bytecode); + res.addBytecodeMapping(bytecode); - return res.append('[').append(index.toJava(indent, tracer)).append(']'); + return res.append('[').append(index.toJava(indent)).append(']'); } @Override 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 34d99a1369..6c5831911f 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java @@ -4,7 +4,6 @@ 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; @@ -25,23 +24,23 @@ protected List getAllExprents(List list) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buffer = new TextBuffer(); buffer.append("assert "); - tracer.addMapping(bytecode); + buffer.addBytecodeMapping(bytecode); if (parameters.get(0) == null) { buffer.append("false"); } else { - buffer.append(parameters.get(0).toJava(indent, tracer)); + buffer.append(parameters.get(0).toJava(indent)); } if (parameters.size() > 1) { buffer.append(" : "); - buffer.append(parameters.get(1).toJava(indent, tracer)); + buffer.append(parameters.get(1).toJava(indent)); } return buffer; 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 7543e180d8..d869a62536 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java @@ -96,7 +96,7 @@ public int getPrecedence() { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { VarType leftType = left.getInferredExprType(null); VarType rightType = right.getInferredExprType(leftType); @@ -126,14 +126,14 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { if (fieldInClassInit) { buffer.append(((FieldExprent) left).getName()); } else { - buffer.append(left.toJava(indent, tracer)); + buffer.append(left.toJava(indent)); } if (right.type == EXPRENT_CONST) { ((ConstExprent) right).adjustConstType(leftType); } - TextBuffer res = right.toJava(indent, tracer); + TextBuffer res = right.toJava(indent); if (condType == CONDITION_NONE && !leftType.isSuperset(rightType) && @@ -151,7 +151,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { buffer.append(condType == CONDITION_NONE ? " = " : OPERATORS[condType]).append(res); - tracer.addMapping(bytecode); + buffer.addStartBytecodeMapping(bytecode); return buffer; } 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 6696793bd4..a21a7b9323 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java @@ -3,9 +3,7 @@ import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.main.DecompilerContext; -import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; @@ -19,14 +17,12 @@ import java.util.*; import java.util.Map.Entry; -import java.util.function.BiFunction; import java.util.function.Function; -import java.util.function.Supplier; public class ConstExprent extends Exprent { private static final Map CHAR_ESCAPES = new HashMap<>(); - private static final Map> UNINLINED_DOUBLES = new HashMap<>(); - private static final Map> UNINLINED_FLOATS = new HashMap<>(); + private static final Map> UNINLINED_DOUBLES = new HashMap<>(); + private static final Map> UNINLINED_FLOATS = new HashMap<>(); static { CHAR_ESCAPES.put(0x8, "\\b"); /* \u0008: backspace BS */ @@ -44,25 +40,25 @@ public class ConstExprent extends Exprent { // This patch is based on work in ForgeFlower submitted by Pokechu22. // Positive and negative e - UNINLINED_DOUBLES.put(Math.E, (tracer, bytecode) -> getDouble(tracer, bytecode, "E", "java/lang/Math")); - UNINLINED_DOUBLES.put(-Math.E, (tracer, bytecode) -> getDouble(tracer, bytecode, "E", "java/lang/Math").prepend("-")); + UNINLINED_DOUBLES.put(Math.E, bytecode -> getDouble(bytecode, "E", "java/lang/Math")); + UNINLINED_DOUBLES.put(-Math.E, bytecode -> getDouble(bytecode, "E", "java/lang/Math").prepend("-")); // Positive and negative pi UNINLINED_DOUBLES.put(Math.PI, ConstExprent::getPiDouble); - UNINLINED_DOUBLES.put(-Math.PI, (tracer, bytecode) -> getPiDouble(tracer, bytecode).prepend("-")); + UNINLINED_DOUBLES.put(-Math.PI, bytecode -> getPiDouble(bytecode).prepend("-")); // Positive and negative pi divisors for (int i = 2; i <= 20; i++) { int finalI = i; - UNINLINED_DOUBLES.put(Math.PI / i, (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" / "+ finalI)); - UNINLINED_DOUBLES.put(-Math.PI / i, (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" / "+ finalI).prepend("-")); + UNINLINED_DOUBLES.put(Math.PI / i, bytecode -> getPiDouble(bytecode).append(" / "+ finalI)); + UNINLINED_DOUBLES.put(-Math.PI / i, bytecode -> getPiDouble(bytecode).append(" / "+ finalI).prepend("-")); } // Positive and negative pi multipliers for (int i = 2; i <= 20; i++) { int finalI = i; - UNINLINED_DOUBLES.put(Math.PI * i, (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" * "+ finalI)); - UNINLINED_DOUBLES.put(-Math.PI * i, (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" * "+ finalI).prepend("-")); + UNINLINED_DOUBLES.put(Math.PI * i, bytecode -> getPiDouble(bytecode).append(" * "+ finalI)); + UNINLINED_DOUBLES.put(-Math.PI * i, bytecode -> getPiDouble(bytecode).append(" * "+ finalI).prepend("-")); } // Extra pi values on the unit circle @@ -72,37 +68,37 @@ public class ConstExprent extends Exprent { if (gcd == 1) { double finalNumerator = numerator; double finalDenominator = denominator; - UNINLINED_DOUBLES.put(Math.PI * (numerator / denominator), (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" * " + finalNumerator + " / " + finalDenominator)); - UNINLINED_DOUBLES.put(-Math.PI * (numerator / denominator), (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" * " + finalNumerator + " / " + finalDenominator).prepend("-")); + UNINLINED_DOUBLES.put(Math.PI * (numerator / denominator), bytecode -> getPiDouble(bytecode).append(" * " + finalNumerator + " / " + finalDenominator)); + UNINLINED_DOUBLES.put(-Math.PI * (numerator / denominator), bytecode -> getPiDouble(bytecode).append(" * " + finalNumerator + " / " + finalDenominator).prepend("-")); if ((float) Math.PI * (float) numerator / (float) denominator != (float) (Math.PI * numerator / denominator)) { - UNINLINED_FLOATS.put((float) Math.PI * ((float) numerator / (float) denominator), (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" * " + finalNumerator + "F / " + finalDenominator + "F").prepend("(float) ")); - UNINLINED_FLOATS.put((float) -Math.PI * ((float) numerator / (float) denominator), (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" * " + finalNumerator + "F / " + finalDenominator + "F").prepend("(float) -")); + UNINLINED_FLOATS.put((float) Math.PI * ((float) numerator / (float) denominator), bytecode -> getPiDouble(bytecode).append(" * " + finalNumerator + "F / " + finalDenominator + "F").prepend("(float) ")); + UNINLINED_FLOATS.put((float) -Math.PI * ((float) numerator / (float) denominator), bytecode -> getPiDouble(bytecode).append(" * " + finalNumerator + "F / " + finalDenominator + "F").prepend("(float) -")); } } } } // Positive and negative 180 / pi - UNINLINED_DOUBLES.put(180.0 / Math.PI, (tracer, bytecode) -> getPiDouble(tracer, bytecode).prepend("180.0 / ")); - UNINLINED_DOUBLES.put(-180.0 / Math.PI, (tracer, bytecode) -> getPiDouble(tracer, bytecode).prepend("-180.0 / ")); + UNINLINED_DOUBLES.put(180.0 / Math.PI, bytecode -> getPiDouble(bytecode).prepend("180.0 / ")); + UNINLINED_DOUBLES.put(-180.0 / Math.PI, bytecode -> getPiDouble(bytecode).prepend("-180.0 / ")); - UNINLINED_FLOATS.put((float)(180.0F / Math.PI), (tracer, bytecode) -> getPiDouble(tracer, bytecode).prepend("180.0F / ")); - UNINLINED_FLOATS.put((float)(-180.0F / Math.PI), (tracer, bytecode) -> getPiDouble(tracer, bytecode).prepend("-180.0F / ")); + UNINLINED_FLOATS.put((float)(180.0F / Math.PI), bytecode -> getPiDouble(bytecode).prepend("180.0F / ")); + UNINLINED_FLOATS.put((float)(-180.0F / Math.PI), bytecode -> getPiDouble(bytecode).prepend("-180.0F / ")); - UNINLINED_FLOATS.put((float)(180.0F / (float)Math.PI), (tracer, bytecode) -> getPiDouble(tracer, bytecode).prepend("180.0F / (float)")); - UNINLINED_FLOATS.put((float)(-180.0F / (float)Math.PI), (tracer, bytecode) -> getPiDouble(tracer, bytecode).prepend("-180.0F / (float)")); + UNINLINED_FLOATS.put((float)(180.0F / (float)Math.PI), bytecode -> getPiDouble(bytecode).prepend("180.0F / (float)")); + UNINLINED_FLOATS.put((float)(-180.0F / (float)Math.PI), bytecode -> getPiDouble(bytecode).prepend("-180.0F / (float)")); // Positive and negative pi / 180 - UNINLINED_DOUBLES.put(Math.PI / 180.0, (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" / 180.0")); - UNINLINED_DOUBLES.put(-Math.PI / 180.0, (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" / 180.0").prepend("-")); + UNINLINED_DOUBLES.put(Math.PI / 180.0, bytecode -> getPiDouble(bytecode).append(" / 180.0")); + UNINLINED_DOUBLES.put(-Math.PI / 180.0, bytecode -> getPiDouble(bytecode).append(" / 180.0").prepend("-")); - UNINLINED_FLOATS.put((float)(Math.PI / 180.0), (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" / 180.0").prepend("(float) ")); - UNINLINED_FLOATS.put((float)(-Math.PI / 180.0), (tracer, bytecode) -> getPiDouble(tracer, bytecode).append(" / 180.0").prepend("-").prepend("(float) ")); + UNINLINED_FLOATS.put((float)(Math.PI / 180.0), bytecode -> getPiDouble(bytecode).append(" / 180.0").prepend("(float) ")); + UNINLINED_FLOATS.put((float)(-Math.PI / 180.0), bytecode -> getPiDouble(bytecode).append(" / 180.0").prepend("-").prepend("(float) ")); UNINLINED_DOUBLES.forEach((key, valueFunction) -> { - UNINLINED_FLOATS.put(key.floatValue(), (tracer, bytecode) -> { - TextBuffer doubleValue = valueFunction.apply(tracer, bytecode); + UNINLINED_FLOATS.put(key.floatValue(), bytecode -> { + TextBuffer doubleValue = valueFunction.apply(bytecode); if (doubleValue.count(" ", 0) > 0) { // As long as all uninlined double values with more than one expression have a space in it, this'll work. doubleValue.prepend("(").append(")"); } @@ -111,23 +107,23 @@ public class ConstExprent extends Exprent { }); // Double and Float constants - UNINLINED_DOUBLES.put(Double.POSITIVE_INFINITY, ((tracer, bytecode) -> getDouble(tracer, bytecode, "POSITIVE_INFINITY", "java/lang/Double"))); - UNINLINED_DOUBLES.put(Double.NEGATIVE_INFINITY, ((tracer, bytecode) -> getDouble(tracer, bytecode, "NEGATIVE_INFINITY", "java/lang/Double"))); - UNINLINED_DOUBLES.put(Double.MAX_VALUE, ((tracer, bytecode) -> getDouble(tracer, bytecode, "MAX_VALUE", "java/lang/Double"))); - UNINLINED_DOUBLES.put(Double.MIN_NORMAL, ((tracer, bytecode) -> getDouble(tracer, bytecode, "MIN_NORMAL", "java/lang/Double"))); - UNINLINED_DOUBLES.put(Double.MIN_VALUE, ((tracer, bytecode) -> getDouble(tracer, bytecode, "MIN_VALUE", "java/lang/Double"))); - UNINLINED_DOUBLES.put(-Double.MAX_VALUE, ((tracer, bytecode) -> getDouble(tracer, bytecode, "MAX_VALUE", "java/lang/Double").prepend("-"))); - UNINLINED_DOUBLES.put(-Double.MIN_NORMAL, ((tracer, bytecode) -> getDouble(tracer, bytecode, "MIN_NORMAL", "java/lang/Double").prepend("-"))); - UNINLINED_DOUBLES.put(-Double.MIN_VALUE, ((tracer, bytecode) -> getDouble(tracer, bytecode, "MIN_VALUE", "java/lang/Double").prepend("-"))); - - UNINLINED_FLOATS.put(Float.POSITIVE_INFINITY, ((tracer, bytecode) -> getFloat(tracer, bytecode, "POSITIVE_INFINITY", "java/lang/Float"))); - UNINLINED_FLOATS.put(Float.NEGATIVE_INFINITY, ((tracer, bytecode) -> getFloat(tracer, bytecode, "NEGATIVE_INFINITY", "java/lang/Float"))); - UNINLINED_FLOATS.put(Float.MAX_VALUE, ((tracer, bytecode) -> getFloat(tracer, bytecode, "MAX_VALUE", "java/lang/Float"))); - UNINLINED_FLOATS.put(Float.MIN_NORMAL, ((tracer, bytecode) -> getFloat(tracer, bytecode, "MIN_NORMAL", "java/lang/Float"))); - UNINLINED_FLOATS.put(Float.MIN_VALUE, ((tracer, bytecode) -> getFloat(tracer, bytecode, "MIN_VALUE", "java/lang/Float"))); - UNINLINED_FLOATS.put(-Float.MAX_VALUE, ((tracer, bytecode) -> getFloat(tracer, bytecode, "MAX_VALUE", "java/lang/Float").prepend("-"))); - UNINLINED_FLOATS.put(-Float.MIN_NORMAL, ((tracer, bytecode) -> getFloat(tracer, bytecode, "MIN_NORMAL", "java/lang/Float").prepend("-"))); - UNINLINED_FLOATS.put(-Float.MIN_VALUE, ((tracer, bytecode) -> getFloat(tracer, bytecode, "MIN_VALUE", "java/lang/Float").prepend("-"))); + UNINLINED_DOUBLES.put(Double.POSITIVE_INFINITY, bytecode -> getDouble(bytecode, "POSITIVE_INFINITY", "java/lang/Double")); + UNINLINED_DOUBLES.put(Double.NEGATIVE_INFINITY, bytecode -> getDouble(bytecode, "NEGATIVE_INFINITY", "java/lang/Double")); + UNINLINED_DOUBLES.put(Double.MAX_VALUE, bytecode -> getDouble(bytecode, "MAX_VALUE", "java/lang/Double")); + UNINLINED_DOUBLES.put(Double.MIN_NORMAL, bytecode -> getDouble(bytecode, "MIN_NORMAL", "java/lang/Double")); + UNINLINED_DOUBLES.put(Double.MIN_VALUE, bytecode -> getDouble(bytecode, "MIN_VALUE", "java/lang/Double")); + UNINLINED_DOUBLES.put(-Double.MAX_VALUE, bytecode -> getDouble(bytecode, "MAX_VALUE", "java/lang/Double").prepend("-")); + UNINLINED_DOUBLES.put(-Double.MIN_NORMAL, bytecode -> getDouble(bytecode, "MIN_NORMAL", "java/lang/Double").prepend("-")); + UNINLINED_DOUBLES.put(-Double.MIN_VALUE, bytecode -> getDouble(bytecode, "MIN_VALUE", "java/lang/Double").prepend("-")); + + UNINLINED_FLOATS.put(Float.POSITIVE_INFINITY, bytecode -> getFloat(bytecode, "POSITIVE_INFINITY", "java/lang/Float")); + UNINLINED_FLOATS.put(Float.NEGATIVE_INFINITY, bytecode -> getFloat(bytecode, "NEGATIVE_INFINITY", "java/lang/Float")); + UNINLINED_FLOATS.put(Float.MAX_VALUE, bytecode -> getFloat(bytecode, "MAX_VALUE", "java/lang/Float")); + UNINLINED_FLOATS.put(Float.MIN_NORMAL, bytecode -> getFloat(bytecode, "MIN_NORMAL", "java/lang/Float")); + UNINLINED_FLOATS.put(Float.MIN_VALUE, bytecode -> getFloat(bytecode, "MIN_VALUE", "java/lang/Float")); + UNINLINED_FLOATS.put(-Float.MAX_VALUE, bytecode -> getFloat(bytecode, "MAX_VALUE", "java/lang/Float").prepend("-")); + UNINLINED_FLOATS.put(-Float.MIN_NORMAL, bytecode -> getFloat(bytecode, "MIN_NORMAL", "java/lang/Float").prepend("-")); + UNINLINED_FLOATS.put(-Float.MIN_VALUE, bytecode -> getFloat(bytecode, "MIN_VALUE", "java/lang/Float").prepend("-")); } private VarType constType; @@ -209,19 +205,20 @@ public List getAllExprents(List list) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { boolean literal = DecompilerContext.getOption(IFernflowerPreferences.LITERALS_AS_IS); boolean ascii = DecompilerContext.getOption(IFernflowerPreferences.ASCII_STRING_CHARACTERS); - tracer.addMapping(bytecode); + TextBuffer buf = new TextBuffer(); + buf.addBytecodeMapping(bytecode); if (constType.type != CodeConstants.TYPE_NULL && value == null) { - return new TextBuffer(ExprProcessor.getCastTypeName(constType)); + return buf.append(ExprProcessor.getCastTypeName(constType)); } switch (constType.type) { case CodeConstants.TYPE_BOOLEAN: - return new TextBuffer(Boolean.toString((Integer)value != 0)); + return buf.append(Boolean.toString((Integer)value != 0)); case CodeConstants.TYPE_CHAR: Integer val = (Integer)value; @@ -235,7 +232,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { ret = TextUtil.charToUnicodeLiteral(c); } } - return new TextBuffer(ret).enclose("'", "'"); + return buf.append(ret).enclose("'", "'"); case CodeConstants.TYPE_BYTE: case CodeConstants.TYPE_BYTECHAR: @@ -245,13 +242,13 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { int intVal = (Integer)value; if (!literal) { if (intVal == Integer.MAX_VALUE) { - return new FieldExprent("MAX_VALUE", "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0, tracer); + return buf.append(new FieldExprent("MAX_VALUE", "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0)); } else if (intVal == Integer.MIN_VALUE) { - return new FieldExprent("MIN_VALUE", "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0, tracer); + return buf.append(new FieldExprent("MIN_VALUE", "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0)); } } - return new TextBuffer(value.toString()); + return buf.append(value.toString()); case CodeConstants.TYPE_LONG: @@ -264,47 +261,47 @@ else if (intVal == Integer.MIN_VALUE) { if (!literal) { if (longVal == Long.MAX_VALUE) { - return new FieldExprent("MAX_VALUE", "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0, tracer); + return buf.append(new FieldExprent("MAX_VALUE", "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0)); } else if (longVal == Long.MIN_VALUE) { - return new FieldExprent("MIN_VALUE", "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0, tracer); + return buf.append(new FieldExprent("MIN_VALUE", "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0)); } } - return new TextBuffer(value.toString()).append('L'); + return buf.append(value.toString()).append('L'); case CodeConstants.TYPE_FLOAT: float floatVal = (Float)value; if (!literal) { if (Float.isNaN(floatVal)) { - return new FieldExprent("NaN", "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); + return buf.append(new FieldExprent("NaN", "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0)); } else if (UNINLINED_FLOATS.containsKey(floatVal)) { - return UNINLINED_FLOATS.get(floatVal).apply(tracer, bytecode); + return buf.append(UNINLINED_FLOATS.get(floatVal).apply(bytecode)); } } else { // Check for special values that can't be used directly in code // (and we can't replace with the constant due to the user requesting not to) if (Float.isNaN(floatVal)) { - return new TextBuffer("0.0F / 0.0F"); + return buf.append("0.0F / 0.0F"); } else if (floatVal == Float.POSITIVE_INFINITY) { - return new TextBuffer("1.0F / 0.0F"); + return buf.append("1.0F / 0.0F"); } else if (floatVal == Float.NEGATIVE_INFINITY) { - return new TextBuffer("-1.0F / 0.0F"); + return buf.append("-1.0F / 0.0F"); } } - return new TextBuffer(trimZeros(Float.toString(floatVal))).append('F'); + return buf.append(trimZeros(Float.toString(floatVal))).append('F'); case CodeConstants.TYPE_DOUBLE: double doubleVal = (Double)value; if (!literal) { if (Double.isNaN(doubleVal)) { - return new FieldExprent("NaN", "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); + return buf.append(new FieldExprent("NaN", "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0)); } else if (UNINLINED_DOUBLES.containsKey(doubleVal)) { - return UNINLINED_DOUBLES.get(doubleVal).apply(tracer, bytecode); + return buf.append(UNINLINED_DOUBLES.get(doubleVal).apply(bytecode)); } // Try to convert the double representation of the value to the float representation, to output the cleanest version of the value. @@ -314,52 +311,52 @@ else if (UNINLINED_DOUBLES.containsKey(doubleVal)) { if (Float.toString(floatRepresentation).length() < Double.toString(doubleVal).length()) { // Check the uninlined values to see if we have one of those if (UNINLINED_FLOATS.containsKey(floatRepresentation)) { - return UNINLINED_FLOATS.get(floatRepresentation).apply(tracer, bytecode); + return buf.append(UNINLINED_FLOATS.get(floatRepresentation).apply(bytecode)); } else { // Return the standard representation if the value is not able to be uninlined - return new TextBuffer(Float.toString(floatRepresentation)).append("F"); + return buf.append(Float.toString(floatRepresentation)).append("F"); } } } } else if (Double.isNaN(doubleVal)) { - return new TextBuffer("0.0 / 0.0"); + return buf.append("0.0 / 0.0"); } else if (doubleVal == Double.POSITIVE_INFINITY) { - return new TextBuffer("1.0 / 0.0"); + return buf.append("1.0 / 0.0"); } else if (doubleVal == Double.NEGATIVE_INFINITY) { - return new TextBuffer("-1.0 / 0.0"); + return buf.append("-1.0 / 0.0"); } - return new TextBuffer(trimZeros(value.toString())); + return buf.append(trimZeros(value.toString())); case CodeConstants.TYPE_NULL: - return new TextBuffer("null"); + return buf.append("null"); case CodeConstants.TYPE_OBJECT: if (constType.equals(VarType.VARTYPE_STRING)) { - return new TextBuffer(convertStringToJava(value.toString(), ascii)).enclose("\"", "\""); + return buf.append(convertStringToJava(value.toString(), ascii)).enclose("\"", "\""); } else if (constType.equals(VarType.VARTYPE_CLASS)) { String stringVal = value.toString(); VarType type = new VarType(stringVal, !stringVal.startsWith("[")); - return new TextBuffer(ExprProcessor.getCastTypeName(type)).append(".class"); + return buf.append(ExprProcessor.getCastTypeName(type)).append(".class"); } } throw new RuntimeException("invalid constant type: " + constType); } - private static TextBuffer getPiDouble(BytecodeMappingTracer tracer, BitSet bytecode) { - return getDouble(tracer, bytecode, "PI", "java/lang/Math"); + private static TextBuffer getPiDouble(BitSet bytecode) { + return getDouble(bytecode, "PI", "java/lang/Math"); } - private static TextBuffer getDouble(BytecodeMappingTracer tracer, BitSet bytecode, String name, String className) { - return new FieldExprent(name, className, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); + private static TextBuffer getDouble(BitSet bytecode, String name, String className) { + return new FieldExprent(name, className, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0); } - private static TextBuffer getFloat(BytecodeMappingTracer tracer, BitSet bytecode, String name, String className) { - return new FieldExprent(name, className, true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); + private static TextBuffer getFloat(BitSet bytecode, String name, String className) { + return new FieldExprent(name, className, true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0); } // Different JVM implementations/version display Floats and Doubles with different number of trailing zeros. @@ -534,7 +531,7 @@ public void getBytecodeRange(BitSet values) { @Override public String toString() { - return "const(" + toJava(0, new BytecodeMappingTracer()) + ")"; + return "const(" + toJava(0) + ")"; } // ***************************************************************************** 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 19079d182b..3b38c29614 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java @@ -4,7 +4,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.main.rels.MethodWrapper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; @@ -17,7 +16,6 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.TextBuffer; -import java.util.ArrayList; import java.util.BitSet; import java.util.List; @@ -67,23 +65,24 @@ public List getAllExprents(List lst) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - tracer.addMapping(bytecode); + public TextBuffer toJava(int indent) { + TextBuffer buf = new TextBuffer(); + buf.addBytecodeMapping(bytecode); if (exitType == EXIT_RETURN) { - TextBuffer buffer = new TextBuffer("return"); + buf.append("return"); if (retType.type != CodeConstants.TYPE_VOID) { VarType ret = retType; if (methodDescriptor != null && methodDescriptor.genericInfo != null && methodDescriptor.genericInfo.returnType != null) { ret = methodDescriptor.genericInfo.returnType; } - buffer.append(' '); + buf.append(' '); - ExprProcessor.getCastedExprent(value, ret, buffer, indent, false, false, false, false, tracer); + ExprProcessor.getCastedExprent(value, ret, buf, indent, false, false, false, false); } - return buffer; + return buf; } else { MethodWrapper method = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); @@ -108,14 +107,14 @@ else if ("java/lang/Exception".equals(exClassName)) { if (classname != null) { VarType exType = new VarType(classname, true); - TextBuffer buffer = new TextBuffer("throw "); - ExprProcessor.getCastedExprent(value, exType, buffer, indent, false, tracer); - return buffer; + buf.append("throw "); + ExprProcessor.getCastedExprent(value, exType, buf, indent, false); + return buf; } } } - return value.toJava(indent, tracer).prepend("throw "); + return buf.append(value.toJava(indent)).prepend("throw "); } } 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 035d738d45..cf6367186a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java @@ -6,11 +6,8 @@ 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.struct.gen.MethodDescriptor; 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.ClassWrapper; 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; @@ -150,10 +147,10 @@ public Exprent copy() { } public TextBuffer toJava() { - return toJava(0, BytecodeMappingTracer.DUMMY); + return toJava(0); } - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { throw new RuntimeException("not implemented"); } @@ -385,6 +382,6 @@ public boolean match(MatchNode matchNode, MatchEngine engine) { @Override public String toString() { - return toJava(0, BytecodeMappingTracer.DUMMY).toString(); + return toJava(0).toString(); } } \ No newline at end of file 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 05c06d8838..2fd3b609e6 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -6,7 +6,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.main.rels.MethodWrapper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; @@ -24,7 +23,6 @@ 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.Collections; import java.util.HashMap; @@ -142,7 +140,7 @@ private boolean isAmbiguous() { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); if (isStatic) { @@ -177,14 +175,13 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { } else { TextBuffer buff = new TextBuffer(); - boolean casted = ExprProcessor.getCastedExprent(instance, new VarType(CodeConstants.TYPE_OBJECT, 0, classname), buff, indent, true, tracer); - String res = buff.toString(); + boolean casted = ExprProcessor.getCastedExprent(instance, new VarType(CodeConstants.TYPE_OBJECT, 0, classname), buff, indent, true); if (casted || instance.getPrecedence() > getPrecedence()) { - res = "(" + res + ")"; + buff.enclose("(", ")"); } - buf.append(res); + buf.append(buff); } if (buf.toString().equals( @@ -198,7 +195,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { buf.append(name); - tracer.addMapping(bytecode); + buf.addStartBytecodeMapping(bytecode); return buf; } 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 36bf5b36a0..945cbd18e0 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -4,12 +4,8 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; import org.jetbrains.java.decompiler.code.CodeConstants; -import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; 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.main.extern.IFernflowerLogger.Severity; -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.struct.gen.VarType; @@ -18,7 +14,6 @@ import org.jetbrains.java.decompiler.util.IntHelper; import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.ListStack; -import org.jetbrains.java.decompiler.util.TextBuffer; import java.util.*; @@ -493,8 +488,9 @@ public void replaceExprent(Exprent oldExpr, Exprent newExpr) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - tracer.addMapping(bytecode); + public TextBuffer toJava(int indent) { + TextBuffer buf = new TextBuffer(); + buf.addBytecodeMapping(bytecode); // If we're an unsigned right shift or lower, this function can be represented as a single leftHand + functionType + rightHand operation. if (this.funcType <= FUNCTION_USHR) { @@ -515,8 +511,8 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { } // Initialize the operands with the defaults - TextBuffer leftOperand = wrapOperandString(this.lstOperands.get(0), false, indent, tracer); - TextBuffer rightOperand = wrapOperandString(this.lstOperands.get(1), true, indent, tracer); + TextBuffer leftOperand = wrapOperandString(this.lstOperands.get(0), false, indent); + TextBuffer rightOperand = wrapOperandString(this.lstOperands.get(1), true, indent); // Check for special cased integers on the right and left hand side, and then return if they are found. // This only applies to bitwise and as well as bitwise or functions. @@ -527,18 +523,20 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { // Check if the right is an int constant and adjust accordingly if (right.type == EXPRENT_CONST && right.getExprType() == VarType.VARTYPE_INT) { Integer value = (Integer) ((ConstExprent)right).getValue(); - rightOperand = new TextBuffer(IntHelper.adjustedIntRepresentation(value)); + rightOperand.setLength(0); + rightOperand.append(IntHelper.adjustedIntRepresentation(value)); } // Check if the left is an int constant and adjust accordingly if (left.type == EXPRENT_CONST && left.getExprType() == VarType.VARTYPE_INT) { Integer value = (Integer) ((ConstExprent)left).getValue(); - leftOperand = new TextBuffer(IntHelper.adjustedIntRepresentation(value)); + leftOperand.setLength(0); + leftOperand.append(IntHelper.adjustedIntRepresentation(value)); } } // Return the applied operands and operators. - return leftOperand + return buf.append(leftOperand) .append(OPERATORS[funcType]) .append(rightOperand); } @@ -557,80 +555,80 @@ else if (left.type == EXPRENT_CONST) { } } - return wrapOperandString(lstOperands.get(0), false, indent, tracer) + return buf.append(wrapOperandString(lstOperands.get(0), false, indent)) .append(OPERATORS[funcType - FUNCTION_EQ + 11]) - .append(wrapOperandString(lstOperands.get(1), true, indent, tracer)); + .append(wrapOperandString(lstOperands.get(1), true, indent)); } switch (funcType) { case FUNCTION_BIT_NOT: - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("~"); + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("~")); case FUNCTION_BOOL_NOT: - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("!"); + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("!")); case FUNCTION_NEG: - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("-"); + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("-")); case FUNCTION_CAST: if (!needsCast) { - return lstOperands.get(0).toJava(indent, tracer); + return buf.append(lstOperands.get(0).toJava(indent)); } - return lstOperands.get(1).toJava(indent, tracer).enclose("(", ")").append(wrapOperandString(lstOperands.get(0), true, indent, tracer)); + return buf.append(lstOperands.get(1).toJava(indent)).enclose("(", ")").append(wrapOperandString(lstOperands.get(0), true, indent)); case FUNCTION_ARRAY_LENGTH: Exprent arr = lstOperands.get(0); - TextBuffer res = wrapOperandString(arr, false, indent, tracer); + buf.append(wrapOperandString(arr, false, indent)); if (arr.getExprType().arrayDim == 0) { VarType objArr = VarType.VARTYPE_OBJECT.resizeArrayDim(1); // type family does not change - res.enclose("((" + ExprProcessor.getCastTypeName(objArr) + ")", ")"); + buf.enclose("((" + ExprProcessor.getCastTypeName(objArr) + ")", ")"); } - return res.append(".length"); + return buf.append(".length"); case FUNCTION_IIF: - return wrapOperandString(lstOperands.get(0), true, indent, tracer) + return buf.append(wrapOperandString(lstOperands.get(0), true, indent)) .append(" ? ") - .append(wrapOperandString(lstOperands.get(1), true, indent, tracer)) + .append(wrapOperandString(lstOperands.get(1), true, indent)) .append(" : ") - .append(wrapOperandString(lstOperands.get(2), true, indent, tracer)); + .append(wrapOperandString(lstOperands.get(2), true, indent)); case FUNCTION_IPP: - return wrapOperandString(lstOperands.get(0), true, indent, tracer).append("++"); + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).append("++")); case FUNCTION_PPI: - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("++"); + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("++")); case FUNCTION_IMM: - return wrapOperandString(lstOperands.get(0), true, indent, tracer).append("--"); + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).append("--")); case FUNCTION_MMI: - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("--"); + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("--")); case FUNCTION_INSTANCEOF: - TextBuffer buffer = wrapOperandString(lstOperands.get(0), true, indent, tracer).append(" instanceof ").append(wrapOperandString(lstOperands.get(1), true, indent, tracer)); + buf.append(wrapOperandString(lstOperands.get(0), true, indent)).append(" instanceof ").append(wrapOperandString(lstOperands.get(1), true, indent)); if (this.lstOperands.size() > 2) { // Pattern instanceof creation- only happens when we have more than 2 exprents - buffer.append(" "); + buf.append(" "); ((VarExprent)this.lstOperands.get(2)).setDefinition(false); - buffer.append(wrapOperandString(this.lstOperands.get(2), true, indent, tracer)); + buf.append(wrapOperandString(this.lstOperands.get(2), true, indent)); } - return buffer; + return buf; case FUNCTION_LCMP: // shouldn't appear in the final code - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("__lcmp__(") + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("__lcmp__(")) .append(", ") - .append(wrapOperandString(lstOperands.get(1), true, indent, tracer)) + .append(wrapOperandString(lstOperands.get(1), true, indent)) .append(")"); case FUNCTION_FCMPL: // shouldn't appear in the final code - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("__fcmpl__(") + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("__fcmpl__(")) .append(", ") - .append(wrapOperandString(lstOperands.get(1), true, indent, tracer)) + .append(wrapOperandString(lstOperands.get(1), true, indent)) .append(")"); case FUNCTION_FCMPG: // shouldn't appear in the final code - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("__fcmpg__(") + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("__fcmpg__(")) .append(", ") - .append(wrapOperandString(lstOperands.get(1), true, indent, tracer)) + .append(wrapOperandString(lstOperands.get(1), true, indent)) .append(")"); case FUNCTION_DCMPL: // shouldn't appear in the final code - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("__dcmpl__(") + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("__dcmpl__(")) .append(", ") - .append(wrapOperandString(lstOperands.get(1), true, indent, tracer)) + .append(wrapOperandString(lstOperands.get(1), true, indent)) .append(")"); case FUNCTION_DCMPG: // shouldn't appear in the final code - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("__dcmpg__(") + return buf.append(wrapOperandString(lstOperands.get(0), true, indent).prepend("__dcmpg__(")) .append(", ") - .append(wrapOperandString(lstOperands.get(1), true, indent, tracer)) + .append(wrapOperandString(lstOperands.get(1), true, indent)) .append(")"); } @@ -648,7 +646,7 @@ else if (left.type == EXPRENT_CONST) { inv.forceUnboxing(true); } } - return wrapOperandString(lstOperands.get(0), true, indent, tracer).prepend("(" + ExprProcessor.getTypeName( + return buf.append(wrapOperandString(lstOperands.get(0), true, indent)).prepend("(" + ExprProcessor.getTypeName( TYPES[funcType - FUNCTION_I2L]) + ")"); } @@ -669,7 +667,7 @@ public VarType getSimpleCastType() { return TYPES[funcType - FUNCTION_I2L]; } - private TextBuffer wrapOperandString(Exprent expr, boolean eq, int indent, BytecodeMappingTracer tracer) { + private TextBuffer wrapOperandString(Exprent expr, boolean eq, int indent) { int myprec = getPrecedence(); int exprprec = expr.getPrecedence(); @@ -684,7 +682,7 @@ private TextBuffer wrapOperandString(Exprent expr, boolean eq, int indent, Bytec } } - TextBuffer res = expr.toJava(indent, tracer); + TextBuffer res = expr.toJava(indent); if (parentheses) { res.enclose("(", ")"); 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 f48f20934e..35a3c89b95 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java @@ -3,16 +3,13 @@ */ package org.jetbrains.java.decompiler.modules.decompiler.exps; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; 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.Set; public class IfExprent extends Exprent { @@ -102,9 +99,10 @@ public List getAllExprents(List lst) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - tracer.addMapping(bytecode); - return condition.toJava(indent, tracer).enclose("if (", ")"); + public TextBuffer toJava(int indent) { + TextBuffer buf = condition.toJava(indent).enclose("if (", ")"); + buf.addStartBytecodeMapping(bytecode); + return buf; } @Override 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 739280adc3..2a9978fb69 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -4,8 +4,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.main.collectors.ImportCollector; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.main.rels.MethodWrapper; import org.jetbrains.java.decompiler.modules.decompiler.ClasspathHelper; @@ -511,13 +509,13 @@ public Exprent copy() { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); String super_qualifier = null; boolean isInstanceThis = false; - tracer.addMapping(bytecode); + buf.addBytecodeMapping(bytecode); if (instance instanceof InvocationExprent) { ((InvocationExprent) instance).markUsingBoxingResult(); @@ -527,7 +525,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { 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(lstParameters.get(0), descriptor.params[0], buf, indent, false, false, true, false, tracer); + ExprProcessor.getCastedExprent(lstParameters.get(0), descriptor.params[0], buf, indent, false, false, true, false); return buf; } @@ -612,16 +610,16 @@ else if (instance != null) { } if (skipCast) { - buf.append(func.getLstOperands().get(0).toJava(indent, tracer)); + buf.append(func.getLstOperands().get(0).toJava(indent)); return buf; } } } - buf.append(instance.toJava(indent, tracer)); + buf.append(instance.toJava(indent)); return buf; } - TextBuffer res = instance.toJava(indent, tracer); + TextBuffer res = instance.toJava(indent); boolean skippedCast = false; @@ -721,14 +719,14 @@ else if (isInstanceThis) { buf.append("this("); } else if (instance != null) { - buf.append(instance.toJava(indent, tracer)).append(".("); + buf.append(instance.toJava(indent)).append(".("); } else { throw new RuntimeException("Unrecognized invocation of " + CodeConstants.INIT_NAME); } } - buf.append(appendParamList(indent, tracer)).append(')'); + buf.append(appendParamList(indent)).append(')'); return buf; } @@ -750,7 +748,7 @@ private static void appendBootstrapArgument(TextBuffer buf, PooledConstant arg) } } - public TextBuffer appendParamList(int indent, BytecodeMappingTracer tracer) { + public TextBuffer appendParamList(int indent) { TextBuffer buf = new TextBuffer(); List mask = null; boolean isEnum = false; @@ -921,7 +919,7 @@ else if (desc != null && desc.getSignature() != null && genericArgs.size() != 0) } // 'byte' and 'short' literals need an explicit narrowing type cast when used as a parameter - ExprProcessor.getCastedExprent(lstParameters.get(i), types[i], buff, indent, true, ambiguous, true, true, tracer); + ExprProcessor.getCastedExprent(lstParameters.get(i), types[i], buff, indent, true, ambiguous, true, true); // the last "new Object[0]" in the vararg call is not printed if (buff.length() > 0) { 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 4f372aeb99..6454296420 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java @@ -4,13 +4,11 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; import org.jetbrains.java.decompiler.main.DecompilerContext; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.TextBuffer; -import java.util.ArrayList; import java.util.BitSet; import java.util.List; @@ -42,18 +40,19 @@ public List getAllExprents(List lst) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - tracer.addMapping(bytecode); + public TextBuffer toJava(int indent) { + TextBuffer buf = new TextBuffer(); + buf.addBytecodeMapping(bytecode); if (monType == MONITOR_ENTER) { // Warn if the synchronized method is synchronizing on null, as that is invalid [https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-14.19] if (this.value.type == EXPRENT_CONST && this.value.getExprType() == VarType.VARTYPE_NULL) { DecompilerContext.getLogger().writeMessage("Created invalid synchronize on null!" , IFernflowerLogger.Severity.WARN); } - return value.toJava(indent, tracer).enclose("synchronized(", ")"); + return buf.append(value.toJava(indent)).enclose("synchronized(", ")"); } else { - return new TextBuffer(); + return buf; } } 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 a2e081147a..4a6e4a6424 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -16,7 +16,6 @@ import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor; import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; import org.jetbrains.java.decompiler.util.TextBuffer; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -27,7 +26,6 @@ import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor; import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.ListStack; -import org.jetbrains.java.decompiler.util.TextBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -316,7 +314,7 @@ public int getPrecedence() { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); if (anonymous) { @@ -329,7 +327,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { String enclosing = null; if (!lambda && constructor != null) { - enclosing = getQualifiedNewInstance(child.anonymousClassType.value, constructor.getLstParameters(), indent, tracer); + enclosing = getQualifiedNewInstance(child.anonymousClassType.value, constructor.getLstParameters(), indent); if (enclosing != null) { buf.append(enclosing).append('.'); } @@ -372,7 +370,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { if (!lambda && constructor != null) { appendParameters(buf, constructor.getGenericArgs()); - buf.append('(').append(constructor.appendParamList(indent, tracer)); + buf.append('(').append(constructor.appendParamList(indent)); } else { appendParameters(buf, genericArgs); @@ -391,16 +389,10 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { } setLambdaGenericTypes(); Exprent methodObject = constructor == null ? null : constructor.getInstance(); - TextBuffer clsBuf = new TextBuffer(); - new ClassWriter().classLambdaToJava(child, clsBuf, methodObject, indent, tracer); - buf.append(clsBuf); - tracer.incrementCurrentSourceLine(clsBuf.countLines()); + new ClassWriter().classLambdaToJava(child, buf, methodObject, indent); } else if (!selfReference) { - TextBuffer clsBuf = new TextBuffer(); - new ClassWriter().classToJava(child, clsBuf, indent, tracer); - buf.append(clsBuf); - tracer.incrementCurrentSourceLine(clsBuf.countLines()); + new ClassWriter().classToJava(child, buf, indent); } } else if (directArrayInit) { @@ -410,7 +402,7 @@ else if (directArrayInit) { if (i > 0) { buf.append(", "); } - ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false, tracer); + ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false); } buf.append('}'); } @@ -419,7 +411,7 @@ else if (newType.arrayDim == 0) { String enclosing = null; if (constructor != null) { - enclosing = getQualifiedNewInstance(newType.value, constructor.getLstParameters(), indent, tracer); + enclosing = getQualifiedNewInstance(newType.value, constructor.getLstParameters(), indent); if (enclosing != null) { buf.append(enclosing).append('.'); } @@ -444,7 +436,7 @@ else if (newType.arrayDim == 0) { int start = enumConst ? 2 : 0; if (!enumConst || start < constructor.getLstParameters().size()) { appendParameters(buf, constructor.getGenericArgs()); - buf.append('(').append(constructor.appendParamList(indent, tracer)).append(')'); + buf.append('(').append(constructor.appendParamList(indent)).append(')'); } } } @@ -461,7 +453,7 @@ else if (isVarArgParam) { if (element.type == EXPRENT_NEW) { ((NewExprent) element).setDirectArrayInit(false); } - ExprProcessor.getCastedExprent(element, leftType, buf, indent, false, tracer); + ExprProcessor.getCastedExprent(element, leftType, buf, indent, false); } // if there is just one element of Object[] type it needs to be casted to resolve ambiguity @@ -479,7 +471,7 @@ else if (isVarArgParam) { for (int i = 0; i < newType.arrayDim; i++) { buf.append('['); if (i < lstDims.size()) { - buf.append(lstDims.get(i).toJava(indent, tracer)); + buf.append(lstDims.get(i).toJava(indent)); } buf.append(']'); } @@ -495,7 +487,7 @@ else if (isVarArgParam) { if (i > 0) { buf.append(", "); } - ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false, tracer); + ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false); } buf.append('}'); } @@ -510,7 +502,7 @@ public static boolean probablySyntheticParameter(String className) { return node != null && node.type == ClassNode.CLASS_ANONYMOUS; } - private static String getQualifiedNewInstance(String classname, List lstParams, int indent, BytecodeMappingTracer tracer) { + private static String getQualifiedNewInstance(String classname, List lstParams, int indent) { ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); if (node != null && node.type != ClassNode.CLASS_ROOT && node.type != ClassNode.CLASS_LOCAL @@ -535,7 +527,7 @@ private static String getQualifiedNewInstance(String classname, List ls } if (isQualifiedNew) { - return enclosing.toJava(indent, tracer).toString(); + return enclosing.toJava(indent).toString(); } } } 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 303a1c53c2..84bdee76d3 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -3,7 +3,6 @@ */ package org.jetbrains.java.decompiler.modules.decompiler.exps; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; @@ -73,9 +72,10 @@ public List getAllExprents(List lst) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - tracer.addMapping(bytecode); - return value.toJava(indent, tracer).enclose("switch(", ")"); + public TextBuffer toJava(int indent) { + TextBuffer buf = value.toJava(indent).enclose("switch(", ")"); + buf.addStartBytecodeMapping(bytecode); + return buf; } @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 ccb92ec853..7fdcefd5f4 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -5,7 +5,6 @@ import org.jetbrains.java.decompiler.main.ClassWriter; 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.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.main.rels.MethodWrapper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -15,7 +14,6 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; import org.jetbrains.java.decompiler.struct.StructClass; -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; @@ -29,9 +27,7 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue; import org.jetbrains.java.decompiler.util.InterpreterUtil; 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.stream.Collectors; @@ -106,15 +102,14 @@ public Exprent copy() { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buffer = new TextBuffer(); - tracer.addMapping(bytecode); + buffer.addBytecodeMapping(bytecode); if (classDef) { ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(varType.value); - new ClassWriter().classToJava(child, buffer, indent, tracer); - tracer.incrementCurrentSourceLine(buffer.countLines()); + new ClassWriter().classToJava(child, buffer, indent); } else { VarVersionPair varVersion = getVarVersionPair(); 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 b597fed7f2..69b07406f1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java @@ -6,7 +6,6 @@ import org.jetbrains.java.decompiler.code.SimpleInstructionSequence; import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.main.DecompilerContext; -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.modules.decompiler.exps.Exprent; @@ -61,9 +60,9 @@ else if (instr.group == CodeConstants.GROUP_SWITCH) { // ***************************************************************************** @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - TextBuffer tb = ExprProcessor.listToJava(varDefinitions, indent, tracer); - tb.append(ExprProcessor.listToJava(exprents, indent, tracer)); + public TextBuffer toJava(int indent) { + TextBuffer tb = ExprProcessor.listToJava(varDefinitions, indent); + tb.append(ExprProcessor.listToJava(exprents, indent)); return tb; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java index 642a54d5ba..35b0495bc2 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java @@ -2,9 +2,7 @@ package org.jetbrains.java.decompiler.modules.decompiler.stats; import org.jetbrains.java.decompiler.code.CodeConstants; -import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.main.DecompilerContext; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.collectors.CounterContainer; import org.jetbrains.java.decompiler.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -96,52 +94,49 @@ public static Statement isHead(Statement head) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { String new_line_separator = DecompilerContext.getNewLineSeparator(); TextBuffer buf = new TextBuffer(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer)); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); boolean labeled = isLabeled(); if (labeled) { buf.appendIndent(indent).append("label").append(this.id.toString()).append(":").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } List lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); if (first.type == TYPE_TRYCATCH && first.varDefinitions.isEmpty() && isFinally && !labeled && !first.isLabeled() && (lstSuccs.isEmpty() || !lstSuccs.get(0).explicit)) { - TextBuffer content = ExprProcessor.jmpWrapper(first, indent, true, tracer); + TextBuffer content = ExprProcessor.jmpWrapper(first, indent, true); content.setLength(content.length() - new_line_separator.length()); - tracer.incrementCurrentSourceLine(-1); buf.append(content); } else { buf.appendIndent(indent).append("try {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); buf.appendIndent(indent).append("}"); } - buf.append(isFinally ? " finally" : - " catch (" + vars.get(0).toJava(indent, tracer) + ")").append(" {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); + if (isFinally) { + buf.append(" finally"); + } else { + buf.append(" catch (").append(vars.get(0).toJava(indent)).append(")"); + } + buf.append(" {").appendLineSeparator(); if (monitor != null) { - buf.appendIndent(indent+1).append("if (").append(monitor.toJava(indent, tracer)).append(") {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); + buf.appendIndent(indent+1).append("if (").append(monitor.toJava(indent)).append(") {").appendLineSeparator(); } - buf.append(ExprProcessor.jmpWrapper(handler, indent + 1 + (monitor != null ? 1 : 0), true, tracer)); + buf.append(ExprProcessor.jmpWrapper(handler, indent + 1 + (monitor != null ? 1 : 0), true)); if (monitor != null) { buf.appendIndent(indent + 1).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } buf.appendIndent(indent).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); return buf; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java index 05aad88f12..45ebdda4aa 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java @@ -7,7 +7,6 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; 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.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -141,37 +140,33 @@ else if (next != statn) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer)); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); if (isLabeled()) { buf.appendIndent(indent).append("label").append(this.id.toString()).append(":").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } if (tryType == NORMAL) { buf.appendIndent(indent).append("try {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } else { buf.appendIndent(indent).append("try ("); if (resources.size() > 1) { buf.appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - buf.append(ExprProcessor.listToJava(resources, indent + 1, tracer)); + buf.append(ExprProcessor.listToJava(resources, indent + 1)); buf.appendIndent(indent); } else { - buf.append(resources.get(0).toJava(indent + 1, tracer)); + buf.append(resources.get(0).toJava(indent + 1)); } buf.append(") {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } - buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); buf.appendIndent(indent).append("}"); for (int i = 1; i < stats.size(); i++) { @@ -180,7 +175,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { BasicBlock block = stat.getBasichead().getBlock(); if (!block.getSeq().isEmpty() && block.getInstruction(0).opcode == CodeConstants.opc_astore) { Integer offset = block.getOldOffset(0); - if (offset > -1) tracer.addMapping(offset); + if (offset > -1) buf.addBytecodeMapping(offset); } buf.append(" catch ("); @@ -194,15 +189,13 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { buf.append(exc_type_name).append(" | "); } } - buf.append(vars.get(i - 1).toJava(indent, tracer)); + buf.append(vars.get(i - 1).toJava(indent)); buf.append(") {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - buf.append(ExprProcessor.jmpWrapper(stat, indent + 1, false, tracer)).appendIndent(indent) + buf.append(ExprProcessor.jmpWrapper(stat, indent + 1, false)).appendIndent(indent) .append("}"); } buf.appendLineSeparator(); - tracer.incrementCurrentSourceLine(); return buf; } 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 e7d29b9a8b..73b3c45818 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java @@ -1,7 +1,6 @@ // 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 org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; @@ -79,59 +78,48 @@ public static Statement isHead(Statement head) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer)); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); if (isLabeled()) { buf.appendIndent(indent).append("label").append(this.id.toString()).append(":").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } switch (looptype) { case LOOP_DO: buf.appendIndent(indent).append("while(true) {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false, tracer)); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false)); buf.appendIndent(indent).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); break; case LOOP_DOWHILE: buf.appendIndent(indent).append("do {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false, tracer)); - buf.appendIndent(indent).append("} while(").append(conditionExprent.get(0).toJava(indent, tracer)).append(");").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false)); + buf.appendIndent(indent).append("} while(").append(conditionExprent.get(0).toJava(indent)).append(");").appendLineSeparator(); break; case LOOP_WHILE: - buf.appendIndent(indent).append("while(").append(conditionExprent.get(0).toJava(indent, tracer)).append(") {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false, tracer)); + buf.appendIndent(indent).append("while(").append(conditionExprent.get(0).toJava(indent)).append(") {").appendLineSeparator(); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false)); buf.appendIndent(indent).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); break; case LOOP_FOR: buf.appendIndent(indent).append("for("); if (initExprent.get(0) != null) { - buf.append(initExprent.get(0).toJava(indent, tracer)); + buf.append(initExprent.get(0).toJava(indent)); } buf.append("; ") - .append(conditionExprent.get(0).toJava(indent, tracer)).append("; ").append(incExprent.get(0).toJava(indent, tracer)).append(") {") + .append(conditionExprent.get(0).toJava(indent)).append("; ").append(incExprent.get(0).toJava(indent)).append(") {") .appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false, tracer)); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false)); buf.appendIndent(indent).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); break; case LOOP_FOREACH: - buf.appendIndent(indent).append("for(").append(initExprent.get(0).toJava(indent, tracer)); + buf.appendIndent(indent).append("for(").append(initExprent.get(0).toJava(indent)); 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)); + buf.append(" : ").append(incExprent.get(0).toJava(indent)).append(") {").appendLineSeparator(); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); buf.appendIndent(indent).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } return buf; 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 c098f3be7e..27a1d73dce 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java @@ -1,7 +1,6 @@ // Copyright 2000-2018 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 org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.util.TextBuffer; import java.util.Collection; @@ -41,7 +40,7 @@ public GeneralStatement(Statement head, Collection statemen // ***************************************************************************** @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); if (isLabeled()) { @@ -50,7 +49,7 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { buf.appendIndent(indent).append("abstract statement {").appendLineSeparator(); for (Statement stat : stats) { - buf.append(stat.toJava(indent + 1, tracer)); + buf.append(stat.toJava(indent + 1)); } buf.appendIndent(indent).append("}"); 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 a020949210..baa21ebe07 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java @@ -1,7 +1,6 @@ // 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 org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; @@ -192,22 +191,26 @@ public static Statement isHead(Statement head) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer)); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); - buf.append(first.toJava(indent, tracer)); + buf.append(first.toJava(indent)); if (isLabeled()) { buf.appendIndent(indent).append("label").append(this.id.toString()).append(":").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } Exprent condition = headexprent.get(0); + buf.appendIndent(indent); // Condition can be null in early processing stages - buf.appendIndent(indent).append((condition == null ? "if " : condition.toJava(indent, tracer).toString())).append(" {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); + if (condition != null) { + buf.append(condition.toJava(indent)); + } else { + buf.append("if "); + } + buf.append(" {").appendLineSeparator(); if (ifstat == null) { boolean semicolon = false; @@ -228,11 +231,10 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { } if(semicolon) { buf.append(";").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } } else { - buf.append(ExprProcessor.jmpWrapper(ifstat, indent + 1, true, tracer)); + buf.append(ExprProcessor.jmpWrapper(ifstat, indent + 1, true)); } boolean elseif = false; @@ -245,22 +247,17 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { || !elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).get(0).explicit)) { // else if buf.appendIndent(indent).append("} else "); - TextBuffer content = ExprProcessor.jmpWrapper(elsestat, indent, false, tracer); + TextBuffer content = ExprProcessor.jmpWrapper(elsestat, indent, false); content.setStart(TextUtil.getIndentString(indent).length()); buf.append(content); elseif = true; } else { - BytecodeMappingTracer else_tracer = new BytecodeMappingTracer(tracer.getCurrentSourceLine() + 1); - TextBuffer content = ExprProcessor.jmpWrapper(elsestat, indent + 1, false, else_tracer); + TextBuffer content = ExprProcessor.jmpWrapper(elsestat, indent + 1, false); if (content.length() > 0) { buf.appendIndent(indent).append("} else {").appendLineSeparator(); - - tracer.setCurrentSourceLine(else_tracer.getCurrentSourceLine()); - tracer.addTracer(else_tracer); - buf.append(content); } } @@ -268,7 +265,6 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { if (!elseif) { buf.appendIndent(indent).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } return buf; 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 cf4b5a4553..ccb940c9ec 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java @@ -1,7 +1,6 @@ // Copyright 2000-2018 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 org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.struct.StructMethod; import org.jetbrains.java.decompiler.util.TextBuffer; @@ -23,8 +22,8 @@ public RootStatement(Statement head, DummyExitStatement dummyExit, StructMethod } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - return ExprProcessor.listToJava(varDefinitions, indent, tracer).append(first.toJava(indent, tracer)); + public TextBuffer toJava(int indent) { + return ExprProcessor.listToJava(varDefinitions, indent).append(first.toJava(indent)); } public DummyExitStatement getDummyExit() { diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java index 8aa6adc71c..0749cdf86d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java @@ -1,7 +1,6 @@ // Copyright 2000-2018 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 org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; @@ -85,15 +84,14 @@ public static Statement isHead2Block(Statement head) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); boolean islabeled = isLabeled(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer)); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); if (islabeled) { buf.appendIndent(indent++).append("label").append(this.id.toString()).append(": {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } boolean notempty = false; @@ -104,10 +102,9 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { if (i > 0 && notempty) { buf.appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } - TextBuffer str = ExprProcessor.jmpWrapper(st, indent, false, tracer); + TextBuffer str = ExprProcessor.jmpWrapper(st, indent, false); buf.append(str); notempty = !str.containsOnlyWhitespaces(); @@ -115,7 +112,6 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { if (islabeled) { buf.appendIndent(indent-1).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } return buf; 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 ecb2bd92a6..79f4d20776 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java @@ -481,10 +481,10 @@ public boolean containsStatementStrict(Statement stat) { } public TextBuffer toJava() { - return toJava(0, BytecodeMappingTracer.DUMMY); + return toJava(0); } - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { throw new RuntimeException("not implemented"); } 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 40c72e6ad7..3968aa8de3 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java @@ -4,7 +4,6 @@ import org.jetbrains.java.decompiler.code.SwitchInstruction; import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.main.DecompilerContext; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.collectors.CounterContainer; import org.jetbrains.java.decompiler.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -104,19 +103,17 @@ public static Statement isHead(Statement head) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer)); - buf.append(first.toJava(indent, tracer)); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + buf.append(first.toJava(indent)); if (isLabeled()) { buf.appendIndent(indent).append("label").append(this.id.toString()).append(":").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } - buf.appendIndent(indent).append(headexprent.get(0).toJava(indent, tracer)).append(" {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); + buf.appendIndent(indent).append(headexprent.get(0).toJava(indent)).append(" {").appendLineSeparator(); VarType switch_type = headexprent.get(0).getExprType(); @@ -146,19 +143,17 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { buf.append(((FieldExprent)value).getName()); } else { - buf.append(value.toJava(indent, tracer)); + buf.append(value.toJava(indent)); } buf.append(":").appendLineSeparator(); } - tracer.incrementCurrentSourceLine(); } - buf.append(ExprProcessor.jmpWrapper(stat, indent + 1, false, tracer)); + buf.append(ExprProcessor.jmpWrapper(stat, indent + 1, false)); } buf.appendIndent(indent).append("}").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); return buf; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java index 2e9d4d25b8..b1c536e5e5 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java @@ -3,7 +3,6 @@ import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.code.cfg.BasicBlock; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.SequenceHelper; import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; @@ -57,35 +56,39 @@ public SynchronizedStatement(Statement head, Statement body, Statement exc) { // ***************************************************************************** @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer)); - buf.append(first.toJava(indent, tracer)); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + buf.append(first.toJava(indent)); if (isLabeled()) { buf.appendIndent(indent).append("label").append(this.id.toString()).append(":").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } Exprent headExpr = headexprent.get(0); + buf.appendIndent(indent); // monitor can be null in early processing stages - buf.appendIndent(indent).append(headExpr == null ? "synchronized " : headExpr.toJava(indent, tracer).toString()).append(" {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); + if (headExpr != null) { + buf.append(headExpr.toJava(indent)); + } else { + buf.append("synchronized "); + } + buf.append(" {").appendLineSeparator(); - buf.append(ExprProcessor.jmpWrapper(body, indent + 1, true, tracer)); + buf.append(ExprProcessor.jmpWrapper(body, indent + 1, true)); - buf.appendIndent(indent).append("}").appendLineSeparator(); - mapMonitorExitInstr(tracer); - tracer.incrementCurrentSourceLine(); + buf.appendIndent(indent).append("}"); + mapMonitorExitInstr(buf); + buf.appendLineSeparator(); return buf; } - private void mapMonitorExitInstr(BytecodeMappingTracer tracer) { + private void mapMonitorExitInstr(TextBuffer buffer) { BasicBlock block = body.getBasichead().getBlock(); if (!block.getSeq().isEmpty() && block.getLastInstruction().opcode == CodeConstants.opc_monitorexit) { Integer offset = block.getOldOffset(block.size() - 1); - if (offset > -1) tracer.addMapping(offset); + if (offset > -1) buffer.addBytecodeMapping(offset); } } diff --git a/src/org/jetbrains/java/decompiler/util/DebugPrinter.java b/src/org/jetbrains/java/decompiler/util/DebugPrinter.java index 71d69efb64..18571db91f 100644 --- a/src/org/jetbrains/java/decompiler/util/DebugPrinter.java +++ b/src/org/jetbrains/java/decompiler/util/DebugPrinter.java @@ -1,14 +1,11 @@ package org.jetbrains.java.decompiler.util; import java.util.BitSet; -import java.util.List; -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; -import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute.LocalVariable; //Debug printer useful for visualizing objects, no real functional value public class DebugPrinter { @@ -87,7 +84,7 @@ private static String printExprent(String indent, Exprent exp, VarProcessor varP 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())); + sb.append(' ').append(exp.toJava(0)); } return sb.toString(); } diff --git a/src/org/jetbrains/java/decompiler/util/Pair.java b/src/org/jetbrains/java/decompiler/util/Pair.java new file mode 100644 index 0000000000..2daeb09cc4 --- /dev/null +++ b/src/org/jetbrains/java/decompiler/util/Pair.java @@ -0,0 +1,36 @@ +package org.jetbrains.java.decompiler.util; + +import java.util.Objects; + +public final class Pair { + public final A a; + public final B b; + + private Pair(A a, B b) { + this.a = a; + this.b = b; + } + + public static Pair of(A a, B b) { + return new Pair<>(a, b); + } + + @Override + public int hashCode() { + return a.hashCode() ^ b.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Pair that = (Pair) o; + return Objects.equals(a, that.a) && Objects.equals(b, that.b); + } + + @Override + public String toString() { + return "Pair{" + a + "," + b + '}'; + } +} diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index 2d09c2d7a4..134854ab51 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -4,6 +4,7 @@ package org.jetbrains.java.decompiler.util; import org.jetbrains.java.decompiler.main.DecompilerContext; +import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import java.util.*; @@ -19,6 +20,7 @@ public class TextBuffer { private final String myIndent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING); private final StringBuilder myStringBuilder; private Map myLineToOffsetMapping = null; + private final Map myBytecodeOffsetMapping = new LinkedHashMap<>(); // bytecode offset -> offset in text public TextBuffer() { myStringBuilder = new StringBuilder(); @@ -80,6 +82,57 @@ public boolean containsOnlyWhitespaces() { return true; } + public void addBytecodeMapping(int bytecodeOffset) { + myBytecodeOffsetMapping.putIfAbsent(new BytecodeMappingKey(bytecodeOffset, null, null), myStringBuilder.length()); + } + + public void addStartBytecodeMapping(int bytecodeOffset) { + myBytecodeOffsetMapping.putIfAbsent(new BytecodeMappingKey(bytecodeOffset, null, null), 0); + } + + public void addBytecodeMapping(BitSet bytecodeOffsets) { + if (bytecodeOffsets == null) { + return; + } + for (int i = bytecodeOffsets.nextSetBit(0); i >= 0; i = bytecodeOffsets.nextSetBit(i + 1)) { + addBytecodeMapping(i); + } + } + + public void addStartBytecodeMapping(BitSet bytecodeOffsets) { + if (bytecodeOffsets == null) { + return; + } + for (int i = bytecodeOffsets.nextSetBit(0); i >= 0; i = bytecodeOffsets.nextSetBit(i + 1)) { + addStartBytecodeMapping(i); + } + } + + public void clearUnassignedBytecodeMappingData() { + myBytecodeOffsetMapping.keySet().removeIf(key -> key.myClass == null); + } + + public Map, BytecodeMappingTracer> getTracers() { + List newlineOffsets = new ArrayList<>(); + for (int i = myStringBuilder.indexOf(myLineSeparator); i != -1; i = myStringBuilder.indexOf(myLineSeparator, i + 1)) { + newlineOffsets.add(i); + } + Map, BytecodeMappingTracer> tracers = new LinkedHashMap<>(); + myBytecodeOffsetMapping.forEach((key, textOffset) -> { + if (key.myClass == null) { + throw new IllegalStateException("getTracers called when not all bytecode offsets have a valid class and method"); + } + BytecodeMappingTracer tracer = tracers.computeIfAbsent(Pair.of(key.myClass, key.myMethod), k -> new BytecodeMappingTracer()); + int lineNo = Collections.binarySearch(newlineOffsets, textOffset); + if (lineNo < 0) { + lineNo = -lineNo - 1; + } + tracer.setCurrentSourceLine(lineNo); + tracer.addMapping(key.myBytecodeOffset); + }); + return tracers; + } + @Override public String toString() { String original = myStringBuilder.toString(); @@ -190,17 +243,27 @@ public void setLength(int position) { } } - public TextBuffer append(TextBuffer buffer) { + public TextBuffer append(TextBuffer buffer, String className, String methodKey) { if (buffer.myLineToOffsetMapping != null && !buffer.myLineToOffsetMapping.isEmpty()) { checkMapCreated(); for (Map.Entry entry : buffer.myLineToOffsetMapping.entrySet()) { myLineToOffsetMapping.put(entry.getKey(), entry.getValue() + myStringBuilder.length()); } } + buffer.myBytecodeOffsetMapping.forEach((key, value) -> { + if (key.myClass == null) { + key = new BytecodeMappingKey(key.myBytecodeOffset, className, methodKey); + } + myBytecodeOffsetMapping.putIfAbsent(key, value + myStringBuilder.length()); + }); myStringBuilder.append(buffer.myStringBuilder); return this; } + public TextBuffer append(TextBuffer buffer) { + return append(buffer, null, null); + } + private void shiftMapping(int shiftOffset) { if (myLineToOffsetMapping != null) { Map newMap = new HashMap<>(); @@ -215,6 +278,7 @@ private void shiftMapping(int shiftOffset) { } myLineToOffsetMapping = newMap; } + myBytecodeOffsetMapping.replaceAll((key, value) -> value + shiftOffset); } private void checkMapCreated() { @@ -282,4 +346,37 @@ public void dumpOriginalLineNumbers(int[] lineMapping) { } } } + + private static final class BytecodeMappingKey { + private final int myBytecodeOffset; + // null signifies the current class + private final String myClass; + private final String myMethod; + + public BytecodeMappingKey(int bytecodeOffset, String className, String methodKey) { + myBytecodeOffset = bytecodeOffset; + myClass = className; + myMethod = methodKey; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BytecodeMappingKey that = (BytecodeMappingKey)o; + return myBytecodeOffset == that.myBytecodeOffset && + Objects.equals(myClass, that.myClass) && + Objects.equals(myMethod, that.myMethod); + } + + @Override + public int hashCode() { + return Objects.hash(myBytecodeOffset, myClass, myMethod); + } + + @Override + public String toString() { + return myClass + ":" + myMethod + ":" + myBytecodeOffset; + } + } } \ No newline at end of file diff --git a/testData/results/pkg/TestAnonymousClass.dec b/testData/results/pkg/TestAnonymousClass.dec index 126a94144a..46f16040d4 100644 --- a/testData/results/pkg/TestAnonymousClass.dec +++ b/testData/results/pkg/TestAnonymousClass.dec @@ -162,16 +162,6 @@ class 'pkg/TestAnonymousClass$8' { } } -class 'pkg/TestAnonymousClass$1' { - method 'foo ()V' { - 0 56 - 1 56 - 2 57 - 3 57 - 4 58 - } -} - class 'pkg/TestAnonymousClass' { method 'foo (I)V' { 0 52 @@ -215,6 +205,16 @@ class 'pkg/TestAnonymousClass' { } } +class 'pkg/TestAnonymousClass$1' { + method 'foo ()V' { + 0 56 + 1 56 + 2 57 + 3 57 + 4 58 + } +} + class 'pkg/TestAnonymousClass$2' { method 'foo (Ljava/lang/String;)V' { 0 71 diff --git a/testData/results/pkg/TestAnonymousParams.dec b/testData/results/pkg/TestAnonymousParams.dec index c5b4f237dd..8d07a1c8cd 100644 --- a/testData/results/pkg/TestAnonymousParams.dec +++ b/testData/results/pkg/TestAnonymousParams.dec @@ -16,15 +16,6 @@ public class TestAnonymousParams { }// 31 } -class 'pkg/TestAnonymousParams$1' { - method 'read ()I' { - 1 11 - 2 11 - 3 11 - 4 11 - } -} - class 'pkg/TestAnonymousParams' { method 'foo (Ljava/io/InputStream;I)V' { 5 8 @@ -37,6 +28,15 @@ class 'pkg/TestAnonymousParams' { } } +class 'pkg/TestAnonymousParams$1' { + method 'read ()I' { + 1 11 + 2 11 + 3 11 + 4 11 + } +} + Lines mapping: 24 <-> 9 27 <-> 12 diff --git a/testData/results/pkg/TestAnonymousSignature.dec b/testData/results/pkg/TestAnonymousSignature.dec index b21ea66f28..95018b9bf0 100644 --- a/testData/results/pkg/TestAnonymousSignature.dec +++ b/testData/results/pkg/TestAnonymousSignature.dec @@ -19,22 +19,6 @@ public class TestAnonymousSignature { }// 39 } -class 'pkg/TestAnonymousSignature$1' { - method 'size ()I' { - 1 10 - 2 10 - 3 10 - 4 10 - } -} - -class 'pkg/TestAnonymousSignature$2' { - method 'compare (Ljava/lang/String;Ljava/lang/String;)I' { - 0 15 - 1 15 - } -} - class 'pkg/TestAnonymousSignature' { method 'main ([Ljava/lang/String;)V' { 0 7 @@ -53,6 +37,22 @@ class 'pkg/TestAnonymousSignature' { } } +class 'pkg/TestAnonymousSignature$1' { + method 'size ()I' { + 1 10 + 2 10 + 3 10 + 4 10 + } +} + +class 'pkg/TestAnonymousSignature$2' { + method 'compare (Ljava/lang/String;Ljava/lang/String;)I' { + 0 15 + 1 15 + } +} + Lines mapping: 25 <-> 8 28 <-> 11 diff --git a/testData/results/pkg/TestClassLambda.dec b/testData/results/pkg/TestClassLambda.dec index 8305f1af3c..ace7f3a6bd 100644 --- a/testData/results/pkg/TestClassLambda.dec +++ b/testData/results/pkg/TestClassLambda.dec @@ -22,17 +22,17 @@ public class TestClassLambda { public void testLambda1() { int a = (int)Math.random();// 39 - Runnable r1 = () -> {// 40 - System.out.println("hello1" + a); + Runnable r1 = () -> { + System.out.println("hello1" + a);// 40 }; - Runnable r2 = () -> {// 41 - System.out.println("hello2" + a); + Runnable r2 = () -> { + System.out.println("hello2" + a);// 41 }; }// 42 public void testLambda2() { - reduce((left, right) -> {// 45 - return Math.max(left, right); + reduce((left, right) -> { + return Math.max(left, right);// 45 }); }// 46 @@ -53,8 +53,8 @@ public class TestClassLambda { List list = new ArrayList();// 62 int bottom = list.size() * 2;// 63 int top = list.size() * 5;// 64 - list.removeIf(s -> {// 65 - return bottom >= s.length() && s.length() <= top; + list.removeIf(s -> { + return bottom >= s.length() && s.length() <= top;// 65 }); }// 66 @@ -77,8 +77,8 @@ public class TestClassLambda { public void nestedLambdas() { int a = 5;// 85 Runnable r1 = () -> {// 86 - Runnable r2 = () -> {// 87 - System.out.println("hello2" + a); + Runnable r2 = () -> { + System.out.println("hello2" + a);// 87 }; System.out.println("hello1" + a);// 88 };// 89 @@ -86,31 +86,6 @@ public class TestClassLambda { } class 'pkg/TestClassLambda' { - method 'lambda$testLambda$0 (ILjava/lang/Integer;)V' { - 0 17 - 1 17 - 2 17 - 3 17 - 4 17 - 5 17 - 6 17 - 7 18 - 8 18 - 9 18 - a 18 - b 18 - c 18 - d 18 - e 18 - f 18 - 10 18 - 11 18 - 12 18 - 13 18 - 14 18 - 15 19 - } - method 'testLambda ()V' { 7 14 8 14 @@ -160,6 +135,42 @@ class 'pkg/TestClassLambda' { 4f 20 } + method 'lambda$testLambda$0 (ILjava/lang/Integer;)V' { + 0 17 + 1 17 + 2 17 + 3 17 + 4 17 + 5 17 + 6 17 + 7 18 + 8 18 + 9 18 + a 18 + b 18 + c 18 + d 18 + e 18 + f 18 + 10 18 + 11 18 + 12 18 + 13 18 + 14 18 + 15 19 + } + + method 'testLambda1 ()V' { + 0 23 + 1 23 + 2 23 + 3 23 + 4 23 + b 24 + 12 27 + 13 30 + } + method 'lambda$testLambda1$1 (I)V' { 0 25 1 25 @@ -192,15 +203,11 @@ class 'pkg/TestClassLambda' { 19 29 } - method 'testLambda1 ()V' { - 0 23 - 1 23 - 2 23 - 3 23 - 4 23 - b 24 - 12 27 - 13 30 + method 'testLambda2 ()V' { + 5 33 + 6 33 + 7 33 + 9 36 } method 'lambda$testLambda2$3 (II)I' { @@ -212,13 +219,6 @@ class 'pkg/TestClassLambda' { 5 34 } - method 'testLambda2 ()V' { - 5 33 - 6 33 - 7 33 - 9 36 - } - method 'testLambda3 ()V' { 5 39 6 39 @@ -237,28 +237,13 @@ class 'pkg/TestClassLambda' { 0 47 1 47 2 47 + 3 48 e 48 f 48 10 48 12 49 } - method 'lambda$testLambda6$4 (IILjava/lang/String;)Z' { - 0 56 - 1 56 - 2 56 - 3 56 - 4 56 - 5 56 - 8 56 - 9 56 - a 56 - b 56 - c 56 - d 56 - 15 56 - } - method 'testLambda6 ()V' { 7 52 8 53 @@ -288,6 +273,22 @@ class 'pkg/TestClassLambda' { 28 58 } + method 'lambda$testLambda6$4 (IILjava/lang/String;)Z' { + 0 56 + 1 56 + 2 56 + 3 56 + 4 56 + 5 56 + 8 56 + 9 56 + a 56 + b 56 + c 56 + d 56 + 15 56 + } + method 'testLambda7 ([Ljava/lang/annotation/Annotation;)V' { 0 61 1 61 @@ -324,20 +325,11 @@ class 'pkg/TestClassLambda' { 1 73 } - method 'lambda$null$5 (I)V' { - 0 80 - 1 80 - 2 80 - a 80 - b 80 - f 80 - 13 80 - 14 80 - 15 80 - 16 80 - 17 80 - 18 80 - 19 81 + method 'nestedLambdas ()V' { + 0 77 + 1 77 + 8 78 + 9 84 } method 'lambda$nestedLambdas$6 (I)V' { @@ -357,11 +349,20 @@ class 'pkg/TestClassLambda' { 20 83 } - method 'nestedLambdas ()V' { - 0 77 - 1 77 - 8 78 - 9 84 + method 'lambda$null$5 (I)V' { + 0 80 + 1 80 + 2 80 + a 80 + b 80 + f 80 + 13 80 + 14 80 + 15 80 + 16 80 + 17 80 + 18 80 + 19 81 } } @@ -374,10 +375,10 @@ Lines mapping: 35 <-> 20 36 <-> 21 39 <-> 24 -40 <-> 25 -41 <-> 28 +40 <-> 26 +41 <-> 29 42 <-> 31 -45 <-> 34 +45 <-> 35 46 <-> 37 49 <-> 40 50 <-> 41 @@ -389,7 +390,7 @@ Lines mapping: 62 <-> 53 63 <-> 54 64 <-> 55 -65 <-> 56 +65 <-> 57 66 <-> 59 69 <-> 62 70 <-> 63 @@ -398,7 +399,7 @@ Lines mapping: 81 <-> 74 85 <-> 78 86 <-> 79 -87 <-> 80 +87 <-> 81 88 <-> 83 89 <-> 84 90 <-> 85 diff --git a/testData/results/pkg/TestClassNestedInitializer.dec b/testData/results/pkg/TestClassNestedInitializer.dec index 5011230eb3..e8702c1c68 100644 --- a/testData/results/pkg/TestClassNestedInitializer.dec +++ b/testData/results/pkg/TestClassNestedInitializer.dec @@ -4,27 +4,15 @@ public class TestClassNestedInitializer { public String secret; public void test() { - TestClassNestedInitializer obj = new TestClassNestedInitializer() {// 22 + TestClassNestedInitializer obj = new TestClassNestedInitializer() { { - this.secret = "one"; + this.secret = "one";// 22 } }; System.out.println(obj.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 6 @@ -42,7 +30,19 @@ class 'pkg/TestClassNestedInitializer' { } } +class 'pkg/TestClassNestedInitializer$1' { + method ' (Lpkg/TestClassNestedInitializer;)V' { + 9 8 + a 8 + b 8 + c 8 + d 8 + e 8 + f 9 + } +} + Lines mapping: -22 <-> 7 +22 <-> 9 23 <-> 12 24 <-> 13 diff --git a/testData/results/pkg/TestClassSimpleBytecodeMapping.dec b/testData/results/pkg/TestClassSimpleBytecodeMapping.dec index 181437a5ca..e051155478 100644 --- a/testData/results/pkg/TestClassSimpleBytecodeMapping.dec +++ b/testData/results/pkg/TestClassSimpleBytecodeMapping.dec @@ -47,20 +47,6 @@ public class TestClassSimpleBytecodeMapping { } } -class 'pkg/TestClassSimpleBytecodeMapping$1' { - method 'run ()V' { - 0 8 - 1 8 - 2 8 - 3 8 - 4 8 - 5 8 - 6 8 - 7 8 - 8 9 - } -} - class 'pkg/TestClassSimpleBytecodeMapping' { method 'test ()I' { 0 4 @@ -139,6 +125,20 @@ class 'pkg/TestClassSimpleBytecodeMapping' { } } +class 'pkg/TestClassSimpleBytecodeMapping$1' { + method 'run ()V' { + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 8 + 6 8 + 7 8 + 8 9 + } +} + class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' { method 'print ()V' { 0 38 diff --git a/testData/results/pkg/TestDoubleBraceInitializers.dec b/testData/results/pkg/TestDoubleBraceInitializers.dec index 7add86498e..8a230133fc 100644 --- a/testData/results/pkg/TestDoubleBraceInitializers.dec +++ b/testData/results/pkg/TestDoubleBraceInitializers.dec @@ -42,30 +42,6 @@ public class TestDoubleBraceInitializers { } } -class 'pkg/TestDoubleBraceInitializers$1' { - method ' (Lpkg/TestDoubleBraceInitializers;)V' { - 9 10 - a 10 - b 10 - c 10 - d 10 - e 10 - 10 11 - 11 11 - 12 11 - 13 11 - 14 11 - 15 11 - 17 12 - 18 12 - 19 12 - 1a 12 - 1b 12 - 1c 12 - 1e 13 - } -} - class 'pkg/TestDoubleBraceInitializers' { method 'test ()V' { 8 8 @@ -92,6 +68,30 @@ class 'pkg/TestDoubleBraceInitializers' { } } +class 'pkg/TestDoubleBraceInitializers$1' { + method ' (Lpkg/TestDoubleBraceInitializers;)V' { + 9 10 + a 10 + b 10 + c 10 + d 10 + e 10 + 10 11 + 11 11 + 12 11 + 13 11 + 14 11 + 15 11 + 17 12 + 18 12 + 19 12 + 1a 12 + 1b 12 + 1c 12 + 1e 13 + } +} + class 'pkg/TestDoubleBraceInitializers$2' { method ' (Lpkg/TestDoubleBraceInitializers;)V' { 9 21 diff --git a/testData/results/pkg/TestDoubleNestedClass.dec b/testData/results/pkg/TestDoubleNestedClass.dec index d4db33f0db..30ed96a38e 100644 --- a/testData/results/pkg/TestDoubleNestedClass.dec +++ b/testData/results/pkg/TestDoubleNestedClass.dec @@ -70,6 +70,19 @@ class 'pkg/TestDoubleNestedClass$2' { } } +class 'pkg/TestDoubleNestedClass$Child1' { + method 'foo (I)Ljava/util/function/Supplier;' { + 0 33 + 1 33 + 2 33 + b 34 + } + + method 'lambda$foo$0 (II)Lpkg/TestDoubleNestedClass;' { + a 35 + } +} + class 'pkg/TestDoubleNestedClass$Child1$1' { method 'test ()Ljava/lang/Object;' { 1 38 @@ -108,17 +121,4 @@ class 'pkg/TestDoubleNestedClass$Child1$1' { } } -class 'pkg/TestDoubleNestedClass$Child1' { - method 'lambda$foo$0 (II)Lpkg/TestDoubleNestedClass;' { - a 35 - } - - method 'foo (I)Ljava/util/function/Supplier;' { - 0 33 - 1 33 - 2 33 - b 34 - } -} - Lines mapping: diff --git a/testData/results/pkg/TestDuplicateLocals.dec b/testData/results/pkg/TestDuplicateLocals.dec index 975a332587..55f15101c5 100644 --- a/testData/results/pkg/TestDuplicateLocals.dec +++ b/testData/results/pkg/TestDuplicateLocals.dec @@ -94,24 +94,30 @@ public class TestDuplicateLocals { } class 'pkg/TestDuplicateLocals' { + method 'lambda$static$1 (Ljava/lang/Object;)Ljava/util/function/Predicate;' { + 5 11 + } + method 'lambda$null$0 (Ljava/lang/Object;)Z' { 0 12 1 12 } - method 'lambda$static$1 (Ljava/lang/Object;)Ljava/util/function/Predicate;' { - 5 11 - } - - method 'lambda$null$2 (Ljava/util/List;Ljava/lang/Object;)V' { - 0 22 - 1 22 - 2 22 - 3 22 - 4 22 - 5 22 - 6 22 - 7 23 + method 'test1 (Ljava/util/List;)V' { + 0 18 + 1 18 + 2 18 + 3 18 + 4 18 + 5 18 + 6 18 + 7 19 + d 19 + e 19 + f 19 + 10 19 + 11 19 + 12 25 } method 'lambda$test1$3 (Ljava/util/List;)V' { @@ -131,32 +137,32 @@ class 'pkg/TestDuplicateLocals' { 15 24 } - method 'test1 (Ljava/util/List;)V' { - 0 18 - 1 18 - 2 18 - 3 18 - 4 18 - 5 18 - 6 18 - 7 19 - d 19 - e 19 - f 19 - 10 19 - 11 19 - 12 25 + method 'lambda$null$2 (Ljava/util/List;Ljava/lang/Object;)V' { + 0 22 + 1 22 + 2 22 + 3 22 + 4 22 + 5 22 + 6 22 + 7 23 } - method 'lambda$null$4 (Ljava/lang/Object;)V' { - 0 32 - 1 32 - 2 32 - 3 32 - 4 32 - 5 32 - 6 32 - 7 33 + method 'test2 (Ljava/util/List;)V' { + 0 28 + 1 28 + 2 28 + 3 28 + 4 28 + 5 28 + 6 28 + 7 29 + d 29 + e 29 + f 29 + 10 29 + 11 29 + 12 35 } method 'lambda$test2$5 (Ljava/util/List;)V' { @@ -176,32 +182,32 @@ class 'pkg/TestDuplicateLocals' { 12 34 } - method 'test2 (Ljava/util/List;)V' { - 0 28 - 1 28 - 2 28 - 3 28 - 4 28 - 5 28 - 6 28 - 7 29 - d 29 - e 29 - f 29 - 10 29 - 11 29 - 12 35 + method 'lambda$null$4 (Ljava/lang/Object;)V' { + 0 32 + 1 32 + 2 32 + 3 32 + 4 32 + 5 32 + 6 32 + 7 33 } - method 'lambda$null$6 (ILjava/lang/Object;)V' { - 0 43 - 1 43 - 2 43 - 3 43 - 4 43 - 5 43 - 6 43 - 7 44 + method 'test3 (Ljava/util/List;)V' { + 0 38 + 1 38 + 2 38 + 3 38 + 4 38 + 5 38 + 6 38 + 7 39 + d 39 + e 39 + f 39 + 10 39 + 11 39 + 12 46 } method 'lambda$test3$7 (Ljava/util/List;)V' { @@ -228,32 +234,32 @@ class 'pkg/TestDuplicateLocals' { 1a 45 } - method 'test3 (Ljava/util/List;)V' { - 0 38 - 1 38 - 2 38 - 3 38 - 4 38 - 5 38 - 6 38 - 7 39 - d 39 - e 39 - f 39 - 10 39 - 11 39 - 12 46 + method 'lambda$null$6 (ILjava/lang/Object;)V' { + 0 43 + 1 43 + 2 43 + 3 43 + 4 43 + 5 43 + 6 43 + 7 44 } - method 'lambda$null$8 (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V' { - 0 53 - 1 53 - 2 53 - 3 53 - 4 53 - 5 53 - 6 53 - 7 54 + method 'test4 (Ljava/util/Map;)V' { + 0 49 + 1 49 + 2 49 + 3 49 + 4 49 + 5 49 + 6 49 + 7 50 + e 50 + f 50 + 10 50 + 11 50 + 12 50 + 13 56 } method 'lambda$test4$9 (Ljava/util/Map;Ljava/lang/String;Ljava/util/List;)V' { @@ -273,21 +279,23 @@ class 'pkg/TestDuplicateLocals' { 13 55 } - method 'test4 (Ljava/util/Map;)V' { - 0 49 - 1 49 - 2 49 - 3 49 - 4 49 - 5 49 - 6 49 - 7 50 - e 50 - f 50 - 10 50 - 11 50 - 12 50 - 13 56 + method 'lambda$null$8 (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V' { + 0 53 + 1 53 + 2 53 + 3 53 + 4 53 + 5 53 + 6 53 + 7 54 + } + + method 'test5 (Ljava/util/Optional;)V' { + 0 59 + 6 59 + 7 59 + 8 59 + 9 62 } method 'lambda$test5$10 (Ljava/lang/Object;)V' { @@ -301,12 +309,12 @@ class 'pkg/TestDuplicateLocals' { 7 61 } - method 'test5 (Ljava/util/Optional;)V' { - 0 59 - 6 59 - 7 59 - 8 59 - 9 62 + method 'test6 (Ljava/util/Optional;)V' { + 0 65 + 7 65 + 8 65 + 9 65 + a 68 } method 'lambda$test6$11 (Ljava/lang/Object;)V' { @@ -329,12 +337,18 @@ class 'pkg/TestDuplicateLocals' { 20 67 } - method 'test6 (Ljava/util/Optional;)V' { - 0 65 - 7 65 - 8 65 - 9 65 - a 68 + method 'test7 (I)Ljava/lang/Integer;' { + 7 71 + 8 71 + 9 71 + a 71 + 10 71 + 11 71 + 12 71 + 13 71 + 14 71 + 15 71 + 16 71 } method 'lambda$test7$12 (Ljava/lang/Integer;)Ljava/lang/Integer;' { @@ -349,23 +363,23 @@ class 'pkg/TestDuplicateLocals' { 8 72 9 72 } +} +class 'pkg/TestDuplicateLocals$Inner' { method 'test7 (I)Ljava/lang/Integer;' { - 7 71 - 8 71 - 9 71 - a 71 - 10 71 - 11 71 - 12 71 - 13 71 - 14 71 - 15 71 - 16 71 + 7 78 + 8 78 + 9 78 + a 78 + 11 78 + 12 78 + 13 78 + 14 78 + 15 78 + 16 78 + 17 78 } -} -class 'pkg/TestDuplicateLocals$Inner' { method 'lambda$test7$0 (Ljava/lang/Integer;)Ljava/lang/Integer;' { 0 79 1 79 @@ -383,31 +397,17 @@ class 'pkg/TestDuplicateLocals$Inner' { e 79 f 79 } - - method 'test7 (I)Ljava/lang/Integer;' { - 7 78 - 8 78 - 9 78 - a 78 - 11 78 - 12 78 - 13 78 - 14 78 - 15 78 - 16 78 - 17 78 - } } class 'pkg/TestDuplicateLocals$Inner2' { + method 'lambda$static$1 (Ljava/lang/Object;)Ljava/util/function/Predicate;' { + 5 86 + } + method 'lambda$null$0 (Ljava/lang/Object;)Z' { 0 87 1 87 } - - method 'lambda$static$1 (Ljava/lang/Object;)Ljava/util/function/Predicate;' { - 5 86 - } } Lines mapping: diff --git a/testData/results/pkg/TestInfiniteLoop.dec b/testData/results/pkg/TestInfiniteLoop.dec index 0a6891b251..3bf56462be 100644 --- a/testData/results/pkg/TestInfiniteLoop.dec +++ b/testData/results/pkg/TestInfiniteLoop.dec @@ -129,11 +129,6 @@ Lines mapping: 80 <-> 66 83 <-> 67 Not mapped: -5 -11 -18 -27 -37 50 61 73 diff --git a/testData/results/pkg/TestLambdaParams.dec b/testData/results/pkg/TestLambdaParams.dec index b2dff823d7..a68576588b 100644 --- a/testData/results/pkg/TestLambdaParams.dec +++ b/testData/results/pkg/TestLambdaParams.dec @@ -5,19 +5,29 @@ import java.util.function.Function; public class TestLambdaParams { public static void toCollection(Object collectionFactory) { Class a = null;// 23 - Function f = r1 -> {// 24 - return collectionFactory; + Function f = r1 -> { + return collectionFactory;// 24 }; - Function f1 = r1 -> {// 25 - return a; + Function f1 = r1 -> { + return a;// 25 }; - Function f2 = r1 -> {// 26 - return r1; + Function f2 = r1 -> { + return r1;// 26 }; }// 27 } class 'pkg/TestLambdaParams' { + method 'toCollection (Ljava/lang/Object;)V' { + 0 6 + 1 6 + 8 7 + f 10 + 15 13 + 16 13 + 17 16 + } + method 'lambda$toCollection$0 (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;' { 0 8 1 8 @@ -32,21 +42,11 @@ class 'pkg/TestLambdaParams' { 0 14 1 14 } - - method 'toCollection (Ljava/lang/Object;)V' { - 0 6 - 1 6 - 8 7 - f 10 - 15 13 - 16 13 - 17 16 - } } Lines mapping: 23 <-> 7 -24 <-> 8 -25 <-> 11 -26 <-> 14 +24 <-> 9 +25 <-> 12 +26 <-> 15 27 <-> 17 diff --git a/testData/results/pkg/TestLocalClass.dec b/testData/results/pkg/TestLocalClass.dec index 2d2ba099ef..3993437475 100644 --- a/testData/results/pkg/TestLocalClass.dec +++ b/testData/results/pkg/TestLocalClass.dec @@ -29,22 +29,12 @@ public abstract class TestLocalClass { class C { } - Supplier constr = () -> {// 30 - return new C(); + Supplier constr = () -> { + return new C();// 30 }; }// 31 } -class 'pkg/TestLocalClass$1Local' { - method 'foo ()V' { - 0 10 - 1 10 - 2 11 - 3 11 - 4 12 - } -} - class 'pkg/TestLocalClass' { method 'foo ()V' { 0 6 @@ -69,13 +59,23 @@ class 'pkg/TestLocalClass' { 2 25 } + method 'bar ()V' { + 6 31 + 7 34 + } + method 'lambda$bar$0 ()Lpkg/TestLocalClass$1C;' { 8 32 } +} - method 'bar ()V' { - 6 31 - 7 34 +class 'pkg/TestLocalClass$1Local' { + method 'foo ()V' { + 0 10 + 1 10 + 2 11 + 3 11 + 4 12 } } @@ -91,5 +91,5 @@ Lines mapping: 22 <-> 22 25 <-> 25 26 <-> 26 -30 <-> 32 +30 <-> 33 31 <-> 35 diff --git a/testData/results/pkg/TestLocalRecord.dec b/testData/results/pkg/TestLocalRecord.dec index b0fde5dda5..5f4f1b46d4 100644 --- a/testData/results/pkg/TestLocalRecord.dec +++ b/testData/results/pkg/TestLocalRecord.dec @@ -34,8 +34,8 @@ public class TestLocalRecord { record R() { } - Supplier constr = () -> {// 29 - return new R(); + Supplier constr = () -> { + return new R();// 29 }; }// 30 } @@ -102,14 +102,14 @@ class 'pkg/TestLocalRecord' { 6 30 } - method 'lambda$test4$0 ()Lpkg/TestLocalRecord$3R;' { - 7 37 - } - method 'test4 ()V' { 5 36 6 39 } + + method 'lambda$test4$0 ()Lpkg/TestLocalRecord$3R;' { + 7 37 + } } class 'pkg/TestLocalRecord$2R' { @@ -128,5 +128,5 @@ Lines mapping: 22 <-> 27 24 <-> 30 25 <-> 31 -29 <-> 37 +29 <-> 38 30 <-> 40 diff --git a/testData/results/pkg/TestMethodReferenceSameName.dec b/testData/results/pkg/TestMethodReferenceSameName.dec index 1ccdfec310..a3c6a6a5b8 100644 --- a/testData/results/pkg/TestMethodReferenceSameName.dec +++ b/testData/results/pkg/TestMethodReferenceSameName.dec @@ -15,6 +15,10 @@ public class TestMethodReferenceSameName { class 'pkg/TestMethodReferenceSameName' { method 'foo ()V' { + 0 6 + 1 6 + 2 6 + 3 6 e 6 f 6 10 6 diff --git a/testData/results/pkg/TestNestedLambdas.dec b/testData/results/pkg/TestNestedLambdas.dec index fa484f684e..257f8d8356 100644 --- a/testData/results/pkg/TestNestedLambdas.dec +++ b/testData/results/pkg/TestNestedLambdas.dec @@ -5,8 +5,8 @@ public class TestNestedLambdas { int x = accept(i -> {// 6 if (i == 0) {// 7 accept(j -> {// 8 - return j == 0 ? accept(k -> {// 9 10 - return i + j; + return j == 0 ? accept(k -> {// 9 + return i + j;// 10 }) : i * j;// 12 }); } @@ -27,34 +27,6 @@ public class TestNestedLambdas { } class 'pkg/TestNestedLambdas' { - method 'lambda$null$0 (III)I' { - 0 8 - 1 8 - 2 8 - 3 8 - } - - method 'lambda$null$1 (II)I' { - 0 7 - 1 7 - b 7 - c 7 - d 7 - f 9 - 10 9 - 11 9 - } - - method 'lambda$test$2 (I)I' { - 0 5 - 1 5 - a 6 - b 6 - c 6 - e 13 - f 13 - } - method 'test ()V' { 5 4 6 4 @@ -70,6 +42,34 @@ class 'pkg/TestNestedLambdas' { 10 16 } + method 'lambda$test$2 (I)I' { + 0 5 + 1 5 + a 6 + b 6 + c 6 + e 13 + f 13 + } + + method 'lambda$null$1 (II)I' { + 0 7 + 1 7 + b 7 + c 7 + d 7 + f 9 + 10 9 + 11 9 + } + + method 'lambda$null$0 (III)I' { + 0 8 + 1 8 + 2 8 + 3 8 + } + method 'accept (Lpkg/TestNestedLambdas$Func;)I' { 0 19 1 19 @@ -87,7 +87,7 @@ Lines mapping: 7 <-> 6 8 <-> 7 9 <-> 8 -10 <-> 8 +10 <-> 9 12 <-> 10 17 <-> 14 20 <-> 16 diff --git a/testData/results/pkg/TestObjectArrays.dec b/testData/results/pkg/TestObjectArrays.dec index 6a5d65d16f..789146efc7 100644 --- a/testData/results/pkg/TestObjectArrays.dec +++ b/testData/results/pkg/TestObjectArrays.dec @@ -32,57 +32,6 @@ public class TestObjectArrays { }// 36 } -class 'pkg/TestObjectArrays$1' { - method ' (Lpkg/TestObjectArrays;)V' { - e 20 - 13 20 - 14 20 - 15 20 - 16 20 - 17 20 - 18 20 - 1a 20 - 1b 20 - 1c 20 - 1d 21 - 1e 21 - 1f 21 - 20 21 - 21 21 - 22 21 - 23 21 - 24 21 - 25 22 - 2a 22 - 2b 22 - 2c 22 - 2e 22 - 2f 22 - 30 22 - 31 23 - 39 23 - 3a 23 - 3b 23 - 3c 23 - 3d 23 - 3e 23 - 3f 23 - 40 23 - 41 23 - 42 23 - 43 23 - 44 24 - } - - method 'hashCode ()I' { - 0 28 - 1 28 - 2 28 - 3 28 - 4 28 - } -} - class 'pkg/TestObjectArrays' { method 'test ()V' { 0 6 @@ -137,6 +86,57 @@ class 'pkg/TestObjectArrays' { } } +class 'pkg/TestObjectArrays$1' { + method ' (Lpkg/TestObjectArrays;)V' { + e 20 + 13 20 + 14 20 + 15 20 + 16 20 + 17 20 + 18 20 + 1a 20 + 1b 20 + 1c 20 + 1d 21 + 1e 21 + 1f 21 + 20 21 + 21 21 + 22 21 + 23 21 + 24 21 + 25 22 + 2a 22 + 2b 22 + 2c 22 + 2e 22 + 2f 22 + 30 22 + 31 23 + 39 23 + 3a 23 + 3b 23 + 3c 23 + 3d 23 + 3e 23 + 3f 23 + 40 23 + 41 23 + 42 23 + 43 23 + 44 24 + } + + method 'hashCode ()I' { + 0 28 + 1 28 + 2 28 + 3 28 + 4 28 + } +} + Lines mapping: 7 <-> 7 9 <-> 9 diff --git a/testData/results/pkg/TestPatternMatchingLocalCapture.dec b/testData/results/pkg/TestPatternMatchingLocalCapture.dec index 4d49d29ef9..8647c7bcad 100644 --- a/testData/results/pkg/TestPatternMatchingLocalCapture.dec +++ b/testData/results/pkg/TestPatternMatchingLocalCapture.dec @@ -13,6 +13,18 @@ public class TestPatternMatchingLocalCapture { }// 12 } +class 'pkg/TestPatternMatchingLocalCapture' { + method 'test (Ljava/lang/Object;)V' { + 0 4 + 3 4 + 4 4 + 5 4 + 6 4 + d 4 + 18 12 + } +} + class 'pkg/TestPatternMatchingLocalCapture$1' { method 'test ()V' { 0 7 @@ -28,18 +40,6 @@ class 'pkg/TestPatternMatchingLocalCapture$1' { } } -class 'pkg/TestPatternMatchingLocalCapture' { - method 'test (Ljava/lang/Object;)V' { - 0 4 - 3 4 - 4 4 - 5 4 - 6 4 - d 4 - 18 12 - } -} - Lines mapping: 5 <-> 5 8 <-> 8 diff --git a/testData/results/pkg/TestPrivateClasses.dec b/testData/results/pkg/TestPrivateClasses.dec index 3ea2740c61..e5efee3c10 100644 --- a/testData/results/pkg/TestPrivateClasses.dec +++ b/testData/results/pkg/TestPrivateClasses.dec @@ -177,6 +177,50 @@ class TestPrivateClasses { } } +class 'pkg/TestPrivateClasses$1' { + method 'run ()V' { + 0 5 + 1 5 + 2 5 + 8 19 + c 19 + d 19 + e 19 + 15 33 + 16 33 + 1b 33 + 1c 33 + 1d 33 + 27 34 + 31 39 + 39 44 + 3a 44 + 3b 44 + 3c 44 + 3d 44 + 3e 44 + 3f 44 + 40 44 + 41 44 + 45 44 + 46 44 + 47 44 + 48 44 + 49 44 + 4a 44 + 4b 44 + 4c 44 + 4d 44 + 51 44 + 52 44 + 53 44 + 54 44 + 55 44 + 56 44 + 58 45 + } +} + class 'pkg/TestPrivateClasses$1$1NonCapturingLocalR1' { method ' (Lpkg/TestPrivateClasses$1;Ljava/lang/String;)V' { 9 11 @@ -239,47 +283,47 @@ class 'pkg/TestPrivateClasses$1$2' { } } -class 'pkg/TestPrivateClasses$1' { +class 'pkg/TestPrivateClasses$2' { method 'run ()V' { - 0 5 - 1 5 - 2 5 - 8 19 - c 19 - d 19 - e 19 - 15 33 - 16 33 - 1b 33 - 1c 33 - 1d 33 - 27 34 - 31 39 - 39 44 - 3a 44 - 3b 44 - 3c 44 - 3d 44 - 3e 44 - 3f 44 - 40 44 - 41 44 - 45 44 - 46 44 - 47 44 - 48 44 - 49 44 - 4a 44 - 4b 44 - 4c 44 - 4d 44 - 51 44 - 52 44 - 53 44 - 54 44 - 55 44 - 56 44 - 58 45 + 0 49 + 1 49 + 2 49 + 8 63 + c 63 + d 63 + e 63 + 15 77 + 16 77 + 1b 77 + 1c 77 + 1d 77 + 27 78 + 31 83 + 39 88 + 3a 88 + 3b 88 + 3c 88 + 3d 88 + 3e 88 + 3f 88 + 40 88 + 41 88 + 45 88 + 46 88 + 47 88 + 48 88 + 49 88 + 4a 88 + 4b 88 + 4c 88 + 4d 88 + 51 88 + 52 88 + 53 88 + 54 88 + 55 88 + 56 88 + 58 89 } } @@ -345,50 +389,6 @@ class 'pkg/TestPrivateClasses$2$2' { } } -class 'pkg/TestPrivateClasses$2' { - method 'run ()V' { - 0 49 - 1 49 - 2 49 - 8 63 - c 63 - d 63 - e 63 - 15 77 - 16 77 - 1b 77 - 1c 77 - 1d 77 - 27 78 - 31 83 - 39 88 - 3a 88 - 3b 88 - 3c 88 - 3d 88 - 3e 88 - 3f 88 - 40 88 - 41 88 - 45 88 - 46 88 - 47 88 - 48 88 - 49 88 - 4a 88 - 4b 88 - 4c 88 - 4d 88 - 51 88 - 52 88 - 53 88 - 54 88 - 55 88 - 56 88 - 58 89 - } -} - class 'pkg/TestPrivateClasses$1NonCapturingLocalM1' { method ' (Ljava/lang/String;)V' { 4 97 @@ -408,49 +408,6 @@ class 'pkg/TestPrivateClasses$1NonCapturingLocalM1' { } } -class 'pkg/TestPrivateClasses$1CapturingLocalM1' { - method ' (ILjava/lang/String;)V' { - 9 111 - a 111 - b 111 - c 111 - d 111 - e 112 - } - - method 'toString ()Ljava/lang/String;' { - 8 115 - 9 115 - a 115 - e 115 - f 115 - 13 115 - 14 115 - 15 115 - 16 115 - 1a 115 - 1b 115 - 1c 115 - 1d 115 - } -} - -class 'pkg/TestPrivateClasses$3' { - method 'call ()Ljava/lang/String;' { - 0 122 - 1 122 - } -} - -class 'pkg/TestPrivateClasses$4' { - method 'call ()Ljava/lang/String;' { - 1 127 - 2 127 - 3 127 - 4 127 - } -} - class 'pkg/TestPrivateClasses' { method 'm1 (Ljava/lang/String;)V' { 4 105 @@ -531,6 +488,49 @@ class 'pkg/TestPrivateClasses' { } } +class 'pkg/TestPrivateClasses$1CapturingLocalM1' { + method ' (ILjava/lang/String;)V' { + 9 111 + a 111 + b 111 + c 111 + d 111 + e 112 + } + + method 'toString ()Ljava/lang/String;' { + 8 115 + 9 115 + a 115 + e 115 + f 115 + 13 115 + 14 115 + 15 115 + 16 115 + 1a 115 + 1b 115 + 1c 115 + 1d 115 + } +} + +class 'pkg/TestPrivateClasses$3' { + method 'call ()Ljava/lang/String;' { + 0 122 + 1 122 + } +} + +class 'pkg/TestPrivateClasses$4' { + method 'call ()Ljava/lang/String;' { + 1 127 + 2 127 + 3 127 + 4 127 + } +} + class 'pkg/TestPrivateClasses$1NonCapturingLocalM2' { method ' (Lpkg/TestPrivateClasses;Ljava/lang/String;)V' { 9 138 diff --git a/testData/results/pkg/TestThrowException.dec b/testData/results/pkg/TestThrowException.dec index 4b2938457f..b4ca681aaf 100644 --- a/testData/results/pkg/TestThrowException.dec +++ b/testData/results/pkg/TestThrowException.dec @@ -17,14 +17,6 @@ public class TestThrowException { }// 18 } -class 'pkg/TestThrowException$1' { - method 'run ()V' { - 0 12 - 1 12 - 2 13 - } -} - class 'pkg/TestThrowException' { method ' (I)V' { 4 6 @@ -40,6 +32,14 @@ class 'pkg/TestThrowException' { } } +class 'pkg/TestThrowException$1' { + method 'run ()V' { + 0 12 + 1 12 + 2 13 + } +} + Lines mapping: 9 <-> 7 10 <-> 8 diff --git a/testData/results/pkg/TestTryLoop.dec b/testData/results/pkg/TestTryLoop.dec index 56a4983d7c..96d95544e1 100644 --- a/testData/results/pkg/TestTryLoop.dec +++ b/testData/results/pkg/TestTryLoop.dec @@ -71,12 +71,3 @@ Lines mapping: Not mapped: 18 21 -28 -29 -30 -32 -33 -34 -35 -36 -37 diff --git a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec index 13fbd82fc5..0469d94f61 100644 --- a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec @@ -144,10 +144,3 @@ Not mapped: 17 22 23 -29 -30 -31 -32 -33 -35 -36 diff --git a/testData/results/pkg/TestUnionType.dec b/testData/results/pkg/TestUnionType.dec index a49f196abf..8e68537a3a 100644 --- a/testData/results/pkg/TestUnionType.dec +++ b/testData/results/pkg/TestUnionType.dec @@ -4,18 +4,13 @@ import java.util.Comparator; public interface TestUnionType { static Comparator comparingInt() { - return (c1, c2) -> {// 8 - return 1; + return (c1, c2) -> { + return 1;// 8 }; } } class 'pkg/TestUnionType' { - method 'lambda$comparingInt$ff46620a$1 (Ljava/lang/Object;Ljava/lang/Object;)I' { - 0 7 - 1 7 - } - method 'comparingInt ()Ljava/util/Comparator;' { 5 6 6 6 @@ -25,7 +20,12 @@ class 'pkg/TestUnionType' { a 6 b 6 } + + method 'lambda$comparingInt$ff46620a$1 (Ljava/lang/Object;Ljava/lang/Object;)I' { + 0 7 + 1 7 + } } Lines mapping: -8 <-> 7 +8 <-> 8 diff --git a/testData/results/pkg/TestWhileTernary10.dec b/testData/results/pkg/TestWhileTernary10.dec index 1914494767..26b7bac076 100644 --- a/testData/results/pkg/TestWhileTernary10.dec +++ b/testData/results/pkg/TestWhileTernary10.dec @@ -15,8 +15,8 @@ public class TestWhileTernary10 { } } - doubles.forEach(d -> {// 19 - ds[0] -= d; + doubles.forEach(d -> { + ds[0] -= d;// 19 }); return ds[0];// 20 } @@ -28,8 +28,8 @@ public class TestWhileTernary10 { ds[0] += (double)i;// 27 } - doubles.forEach(d -> {// 30 - ds[0] -= d; + doubles.forEach(d -> { + ds[0] -= d;// 30 }); return ds[0];// 31 } @@ -48,25 +48,14 @@ public class TestWhileTernary10 { } } - doubles.forEach(d -> {// 49 - ds[0] -= d; + doubles.forEach(d -> { + ds[0] -= d;// 49 }); return ds[0];// 50 } } class 'pkg/TestWhileTernary10' { - method 'lambda$test$0 ([DLjava/lang/Double;)V' { - 0 18 - 1 18 - 4 18 - 5 18 - 6 18 - 7 18 - 9 18 - a 19 - } - method 'test (ZILjava/util/stream/Stream;)D' { 5 6 6 6 @@ -123,15 +112,15 @@ class 'pkg/TestWhileTernary10' { 57 20 } - method 'lambda$test1$1 ([DLjava/lang/Double;)V' { - 0 31 - 1 31 - 4 31 - 5 31 - 6 31 - 7 31 - 9 31 - a 32 + method 'lambda$test$0 ([DLjava/lang/Double;)V' { + 0 18 + 1 18 + 4 18 + 5 18 + 6 18 + 7 18 + 9 18 + a 19 } method 'test1 (ZILjava/util/stream/Stream;)D' { @@ -174,15 +163,15 @@ class 'pkg/TestWhileTernary10' { 41 33 } - method 'lambda$test2$2 ([DLjava/lang/Double;)V' { - 0 51 - 1 51 - 4 51 - 5 51 - 6 51 - 7 51 - 9 51 - a 52 + method 'lambda$test1$1 ([DLjava/lang/Double;)V' { + 0 31 + 1 31 + 4 31 + 5 31 + 6 31 + 7 31 + 9 31 + a 32 } method 'test2 (ZILjava/util/stream/Stream;)D' { @@ -251,6 +240,17 @@ class 'pkg/TestWhileTernary10' { 66 53 67 53 } + + method 'lambda$test2$2 ([DLjava/lang/Double;)V' { + 0 51 + 1 51 + 4 51 + 5 51 + 6 51 + 7 51 + 9 51 + a 52 + } } Lines mapping: @@ -260,12 +260,12 @@ Lines mapping: 11 <-> 11 13 <-> 12 14 <-> 13 -19 <-> 18 +19 <-> 19 20 <-> 21 24 <-> 25 26 <-> 27 27 <-> 28 -30 <-> 31 +30 <-> 32 31 <-> 34 35 <-> 38 37 <-> 40 @@ -274,5 +274,5 @@ Lines mapping: 40 <-> 43 42 <-> 44 43 <-> 45 -49 <-> 51 +49 <-> 52 50 <-> 54 From faf5ea0baf898b103203a8eda2e51e073896ede8 Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 14 Nov 2021 22:04:01 +0000 Subject: [PATCH 08/85] Formatting --- .../java/decompiler/main/ClassWriter.java | 33 +- .../decompiler/main/ClassesProcessor.java | 1 + .../decompiler/main/DecompilerContext.java | 9 +- .../java/decompiler/main/RecordHelper.java | 9 +- .../main/extern/IFernflowerPreferences.java | 2 + .../modules/decompiler/exps/Exprent.java | 6 + .../modules/decompiler/exps/FieldExprent.java | 39 +- .../decompiler/exps/FunctionExprent.java | 122 +- .../modules/decompiler/exps/IfExprent.java | 7 +- .../decompiler/exps/InvocationExprent.java | 42 +- .../modules/decompiler/exps/NewExprent.java | 12 +- .../modules/decompiler/exps/VarExprent.java | 5 + .../modules/decompiler/stats/DoStatement.java | 29 +- .../java/decompiler/util/TextBuffer.java | 221 ++++ .../java/decompiler/SingleClassesTest.java | 15 +- testData/kt25937/kt/Kt25937Kt.java | 4 +- testData/kt25937/kt/Kt25937_1Kt.java | 50 +- testData/results/pkg/TestAnonymousClass.dec | 240 ++-- .../pkg/TestAnonymousClassConstructor.dec | 378 +++--- .../pkg/TestBinaryOperationWrapping.dec | 148 +++ testData/results/pkg/TestClassLambda.dec | 346 +++--- .../results/pkg/TestDoubleNestedClass.dec | 72 +- testData/results/pkg/TestDuplicateLocals.dec | 482 ++++---- testData/results/pkg/TestIfLoop.dec | 191 +-- testData/results/pkg/TestLambdaParams.dec | 40 +- testData/results/pkg/TestLocalClass.dec | 12 +- testData/results/pkg/TestLocalRecord.dec | 12 +- .../results/pkg/TestLongMethodDeclaration.dec | 32 + .../results/pkg/TestLongMethodInvocation.dec | 293 +++++ testData/results/pkg/TestMethodHandles.dec | 62 +- testData/results/pkg/TestNestedLambdas.dec | 80 +- testData/results/pkg/TestPrimitives.dec | 1031 +++++++++-------- testData/results/pkg/TestRecordBig.dec | 21 + testData/results/pkg/TestStaticInit.dec | 14 +- testData/results/pkg/TestSuspendLambdaKt.dec | 138 +-- .../pkg/TestSwitchPatternMatching2.dec | 140 +-- .../pkg/TestSwitchPatternMatching5.dec | 256 ++-- .../TestSwitchPatternMatchingConstructor1.dec | 108 +- testData/results/pkg/TestUnionType.dec | 10 +- testData/results/pkg/TestWhileTernary10.dec | 304 +++-- testData/src/java16/pkg/TestRecordBig.java | 21 + .../pkg/TestBinaryOperationWrapping.java | 14 + .../java8/pkg/TestLongMethodDeclaration.java | 22 + .../java8/pkg/TestLongMethodInvocation.java | 72 ++ 44 files changed, 3088 insertions(+), 2057 deletions(-) create mode 100644 testData/results/pkg/TestBinaryOperationWrapping.dec create mode 100644 testData/results/pkg/TestLongMethodDeclaration.dec create mode 100644 testData/results/pkg/TestLongMethodInvocation.dec create mode 100644 testData/results/pkg/TestRecordBig.dec create mode 100644 testData/src/java16/pkg/TestRecordBig.java create mode 100644 testData/src/java8/pkg/TestBinaryOperationWrapping.java create mode 100644 testData/src/java8/pkg/TestLongMethodDeclaration.java create mode 100644 testData/src/java8/pkg/TestLongMethodInvocation.java diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 6ee438f77b..656efe2c14 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -518,47 +518,51 @@ else if (components != null) { if (components != null) { buffer.append('('); - RecordHelper.appendRecordComponents(buffer, cl, components); + RecordHelper.appendRecordComponents(buffer, cl, components, indent); buffer.append(')'); } - buffer.append(' '); + buffer.pushNewlineGroup(indent, 1); if (!isEnum && !isInterface && components == null && cl.superClass != null) { VarType supertype = new VarType(cl.superClass.getString(), true); if (!VarType.VARTYPE_OBJECT.equals(supertype)) { + buffer.appendPossibleNewline(" "); buffer.append("extends "); buffer.append(ExprProcessor.getCastTypeName(descriptor == null ? supertype : descriptor.superclass)); - buffer.append(' '); } } if (!isAnnotation) { int[] interfaces = cl.getInterfaces(); if (interfaces.length > 0) { + buffer.appendPossibleNewline(" "); buffer.append(isInterface ? "extends " : "implements "); for (int i = 0; i < interfaces.length; i++) { if (i > 0) { - buffer.append(", "); + buffer.append(","); + buffer.appendPossibleNewline(" "); } buffer.append(ExprProcessor.getCastTypeName(descriptor == null ? new VarType(cl.getInterface(i), true) : descriptor.superinterfaces.get(i))); } - buffer.append(' '); } } if (isSealed) { + buffer.appendPossibleNewline(" "); buffer.append("permits "); for (int i = 0; i < permittedSubClasses.size(); i++) { if (i > 0) { - buffer.append(", "); + buffer.append(","); + buffer.appendPossibleNewline(" "); } buffer.append(ExprProcessor.getCastTypeName(new VarType(permittedSubClasses.get(i), true))); } - buffer.append(' '); } - buffer.append('{').appendLineSeparator(); + buffer.popNewlineGroup(); + + buffer.append(" {").appendLineSeparator(); } private static boolean isSuperClassSealed(StructClass cl) { @@ -880,6 +884,10 @@ else if (CodeConstants.CLINIT_NAME.equals(name)) { lastVisibleParameterIndex = i; } } + if (lastVisibleParameterIndex != -1) { + buffer.pushNewlineGroup(indent, 1); + buffer.appendPossibleNewline(); + } List methodParameters = null; if (DecompilerContext.getOption(IFernflowerPreferences.USE_METHOD_PARAMETERS)) { @@ -896,11 +904,13 @@ else if (CodeConstants.CLINIT_NAME.equals(name)) { //if (init && !isEnum && ((node.access & CodeConstants.ACC_STATIC) == 0) && node.type == ClassNode.CLASS_MEMBER) // index++; + buffer.pushNewlineGroup(indent, 0); for (int i = start; i < md.params.length; i++) { VarType parameterType = hasDescriptor && paramCount < descriptor.parameterTypes.size() ? descriptor.parameterTypes.get(paramCount) : md.params[i]; if (mask == null || mask.get(i) == null) { if (paramCount > 0) { - buffer.append(", "); + buffer.append(","); + buffer.appendPossibleNewline(" "); } appendParameterAnnotations(buffer, mt, paramCount); @@ -951,7 +961,12 @@ else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarT index += parameterType.stackSize; } + buffer.popNewlineGroup(); + if (lastVisibleParameterIndex != -1) { + buffer.appendPossibleNewline("", true); + buffer.popNewlineGroup(); + } buffer.append(')'); StructExceptionsAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_EXCEPTIONS); diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index 07d1dc0b05..c995d5928c 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -442,6 +442,7 @@ else if (moduleInfo) { TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE); new ClassWriter().classToJava(root, classBuffer, 0); + classBuffer.reformat(); classBuffer.getTracers().forEach((classAndMethod, tracer) -> { // get the class by name StructClass clazz = DecompilerContext.getStructContext().getClass(classAndMethod.a); diff --git a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java index 0837c90a1b..b540763723 100644 --- a/src/org/jetbrains/java/decompiler/main/DecompilerContext.java +++ b/src/org/jetbrains/java/decompiler/main/DecompilerContext.java @@ -11,7 +11,6 @@ import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor; import org.jetbrains.java.decompiler.struct.StructContext; -import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -97,6 +96,14 @@ public static boolean getOption(String key) { return "1".equals(getProperty(key)); } + public static int getIntOption(String key) { + try { + return Integer.parseInt((String) getProperty(key)); + } catch (NumberFormatException e) { + return 0; + } + } + public static String getNewLineSeparator() { return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ? IFernflowerPreferences.LINE_SEPARATOR_UNX : IFernflowerPreferences.LINE_SEPARATOR_WIN; diff --git a/src/org/jetbrains/java/decompiler/main/RecordHelper.java b/src/org/jetbrains/java/decompiler/main/RecordHelper.java index 8867781f91..d851d5ac55 100644 --- a/src/org/jetbrains/java/decompiler/main/RecordHelper.java +++ b/src/org/jetbrains/java/decompiler/main/RecordHelper.java @@ -26,15 +26,20 @@ public static boolean isHiddenRecordMethod(StructClass cl, StructMethod mt, Root (mt.getName().equals(CodeConstants.INIT_NAME) && !hasAnnotations(mt) && isDefaultRecordConstructor(cl, root)); } - public static void appendRecordComponents(TextBuffer buffer, StructClass cl, List components) { + public static void appendRecordComponents(TextBuffer buffer, StructClass cl, List components, int indent) { + buffer.pushNewlineGroup(indent, 1); for (int i = 0; i < components.size(); i++) { StructRecordComponent cd = components.get(i); if (i > 0) { - buffer.append(", "); + buffer.append(","); + buffer.appendPossibleNewline(" "); + } else { + buffer.appendPossibleNewline(); } boolean varArgComponent = i == components.size() - 1 && isVarArgRecord(cl); recordComponentToJava(buffer, cl, cd, i, varArgComponent); } + buffer.popNewlineGroup(); } private static Exprent getSimpleReturnValue(RootStatement root) { diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java index 59ae1f64f0..31ee18a40e 100644 --- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java +++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java @@ -50,6 +50,7 @@ public interface IFernflowerPreferences { String USER_RENAMER_CLASS = "urc"; String NEW_LINE_SEPARATOR = "nls"; String INDENT_STRING = "ind"; + String PREFERRED_LINE_LENGTH = "pll"; String BANNER = "ban"; String THREADS = "thr"; @@ -113,6 +114,7 @@ static Map getDefaults() { defaults.put(RENAME_ENTITIES, "0"); defaults.put(NEW_LINE_SEPARATOR, (InterpreterUtil.IS_WINDOWS ? "0" : "1")); defaults.put(INDENT_STRING, " "); + defaults.put(PREFERRED_LINE_LENGTH, "120"); defaults.put(BANNER, ""); defaults.put(UNIT_TEST_MODE, "0"); defaults.put(DUMP_ORIGINAL_LINES, "0"); 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 cf6367186a..54f9f8ea19 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java @@ -333,6 +333,12 @@ protected void wrapInCast(VarType left, VarType right, TextBuffer buf, int prece public void setInvocationInstance() {} + public void setIsQualifier() {} + + public boolean allowNewlineAfterQualifier() { + return true; + } + // ***************************************************************************** // 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 2fd3b609e6..518f7e8a7e 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -36,6 +36,7 @@ public class FieldExprent extends Exprent { private Exprent instance; private final FieldDescriptor descriptor; private boolean forceQualified = false; + private boolean isQualifier = false; public FieldExprent(LinkConstant cn, Exprent instance, BitSet bytecodeOffsets) { this(cn.elementname, cn.classname, instance == null, instance, FieldDescriptor.parseDescriptor(cn.descriptor), bytecodeOffsets); @@ -144,8 +145,7 @@ public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); if (isStatic) { - ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); - if (node == null || !classname.equals(node.classStruct.qualifiedName) || isAmbiguous() || forceQualified) { + if (useQualifiedStatic()) { buf.append(DecompilerContext.getImportCollector().getShortNameInClassContext(ExprProcessor.buildJavaClassName(classname))); buf.append("."); } @@ -174,6 +174,12 @@ public TextBuffer toJava(int indent) { TextUtil.writeQualifiedSuper(buf, super_qualifier); } else { + if (!isQualifier) { + buf.pushNewlineGroup(indent, 1); + } + if (instance != null) { + instance.setIsQualifier(); + } TextBuffer buff = new TextBuffer(); boolean casted = ExprProcessor.getCastedExprent(instance, new VarType(CodeConstants.TYPE_OBJECT, 0, classname), buff, indent, true); @@ -182,6 +188,12 @@ public TextBuffer toJava(int indent) { } buf.append(buff); + if (instance != null && instance.allowNewlineAfterQualifier()) { + buf.appendPossibleNewline(); + } + if (!isQualifier) { + buf.popNewlineGroup(); + } } if (buf.toString().equals( @@ -193,13 +205,18 @@ public TextBuffer toJava(int indent) { } } - buf.append(name); + buf.addBytecodeMapping(bytecode); - buf.addStartBytecodeMapping(bytecode); + buf.append(name); return buf; } + private boolean useQualifiedStatic() { + ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); + return node == null || !classname.equals(node.classStruct.qualifiedName) || isAmbiguous() || forceQualified; + } + @Override public void replaceExprent(Exprent oldExpr, Exprent newExpr) { if (oldExpr == instance) { @@ -250,7 +267,19 @@ public void getBytecodeRange(BitSet values) { measureBytecode(values); } - // ***************************************************************************** + @Override + public void setIsQualifier() { + isQualifier = true; + } + + @Override + public boolean allowNewlineAfterQualifier() { + if (isStatic && !useQualifiedStatic()) { + return false; + } + return super.allowNewlineAfterQualifier(); + } +// ***************************************************************************** // 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 945cbd18e0..448d12c421 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -106,26 +106,26 @@ public class FunctionExprent extends Exprent { }; private static final String[] OPERATORS = { - " + ", - " - ", - " * ", - " / ", - " & ", - " | ", - " ^ ", - " % ", - " << ", - " >> ", - " >>> ", - " == ", - " != ", - " < ", - " >= ", - " > ", - " <= ", - " && ", - " || ", - " + " + "+", + "-", + "*", + "/", + "&", + "|", + "^", + "%", + "<<", + ">>", + ">>>", + "==", + "!=", + "<", + ">=", + ">", + "<=", + "&&", + "||", + "+" }; private static final int[] PRECEDENCE = { @@ -189,6 +189,7 @@ public class FunctionExprent extends Exprent { private VarType implicitType; private final List lstOperands; private boolean needsCast = true; + private boolean disableNewlineGroupCreation = false; public FunctionExprent(int funcType, ListStack stack, BitSet bytecodeOffsets) { this(funcType, new ArrayList<>(), bytecodeOffsets); @@ -511,8 +512,8 @@ public TextBuffer toJava(int indent) { } // Initialize the operands with the defaults - TextBuffer leftOperand = wrapOperandString(this.lstOperands.get(0), false, indent); - TextBuffer rightOperand = wrapOperandString(this.lstOperands.get(1), true, indent); + TextBuffer leftOperand = wrapOperandString(this.lstOperands.get(0), false, indent, true); + TextBuffer rightOperand = wrapOperandString(this.lstOperands.get(1), true, indent, true); // Check for special cased integers on the right and left hand side, and then return if they are found. // This only applies to bitwise and as well as bitwise or functions. @@ -536,9 +537,16 @@ public TextBuffer toJava(int indent) { } // Return the applied operands and operators. - return buf.append(leftOperand) - .append(OPERATORS[funcType]) + if (!disableNewlineGroupCreation) { + buf.pushNewlineGroup(indent, 1); + } + buf.append(leftOperand) + .append(" ").append(OPERATORS[funcType]).appendPossibleNewline(" ") .append(rightOperand); + if (!disableNewlineGroupCreation) { + buf.popNewlineGroup(); + } + return buf; } // try to determine more accurate type for 'char' literals @@ -555,9 +563,16 @@ else if (left.type == EXPRENT_CONST) { } } - return buf.append(wrapOperandString(lstOperands.get(0), false, indent)) - .append(OPERATORS[funcType - FUNCTION_EQ + 11]) - .append(wrapOperandString(lstOperands.get(1), true, indent)); + if (!disableNewlineGroupCreation) { + buf.pushNewlineGroup(indent, 1); + } + buf.append(wrapOperandString(lstOperands.get(0), false, indent, true)) + .append(" ").append(OPERATORS[funcType - FUNCTION_EQ + 11]).appendPossibleNewline(" ") + .append(wrapOperandString(lstOperands.get(1), true, indent, true)); + if (!disableNewlineGroupCreation) { + buf.popNewlineGroup(); + } + return buf; } switch (funcType) { @@ -582,11 +597,14 @@ else if (left.type == EXPRENT_CONST) { } return buf.append(".length"); case FUNCTION_IIF: - return buf.append(wrapOperandString(lstOperands.get(0), true, indent)) - .append(" ? ") + buf.pushNewlineGroup(indent, 1); + buf.append(wrapOperandString(lstOperands.get(0), true, indent)) + .appendPossibleNewline(" ").append("? ") .append(wrapOperandString(lstOperands.get(1), true, indent)) - .append(" : ") + .appendPossibleNewline(" ").append(": ") .append(wrapOperandString(lstOperands.get(2), true, indent)); + buf.popNewlineGroup(); + return buf; case FUNCTION_IPP: return buf.append(wrapOperandString(lstOperands.get(0), true, indent).append("++")); case FUNCTION_PPI: @@ -656,6 +674,9 @@ else if (left.type == EXPRENT_CONST) { @Override public int getPrecedence() { + if (funcType == FUNCTION_CAST && !doesCast()) { + return lstOperands.get(0).getPrecedence(); + } return getPrecedence(funcType); } @@ -668,6 +689,10 @@ public VarType getSimpleCastType() { } private TextBuffer wrapOperandString(Exprent expr, boolean eq, int indent) { + return wrapOperandString(expr, eq, indent, false); + } + + private TextBuffer wrapOperandString(Exprent expr, boolean eq, int indent, boolean newlineGroup) { int myprec = getPrecedence(); int exprprec = expr.getPrecedence(); @@ -682,10 +707,30 @@ private TextBuffer wrapOperandString(Exprent expr, boolean eq, int indent) { } } + if (newlineGroup && !parentheses && myprec == exprprec) { + if (expr.type == Exprent.EXPRENT_FUNCTION) { + FunctionExprent funcExpr = (FunctionExprent) expr; + if (funcExpr.getFuncType() == FUNCTION_CAST && !funcExpr.doesCast()) { + Exprent subExpr = funcExpr.getLstOperands().get(0); + if (subExpr.type == Exprent.EXPRENT_FUNCTION) { + funcExpr = (FunctionExprent) subExpr; + } + } + funcExpr.disableNewlineGroupCreation = true; + } + } + TextBuffer res = expr.toJava(indent); if (parentheses) { - res.enclose("(", ")"); + TextBuffer oldRes = res; + res = new TextBuffer().append("("); + res.pushNewlineGroup(indent, 1); + res.appendPossibleNewline(); + res.append(oldRes); + res.appendPossibleNewline("", true); + res.popNewlineGroup(); + res.append(")"); } return res; @@ -736,6 +781,21 @@ public void setInvocationInstance() { } } + @Override + public void setIsQualifier() { + if (funcType == FUNCTION_CAST && !doesCast()) { + lstOperands.get(0).setIsQualifier(); + } + } + + @Override + public boolean allowNewlineAfterQualifier() { + if (funcType == FUNCTION_CAST && !doesCast()) { + return lstOperands.get(0).allowNewlineAfterQualifier(); + } + return super.allowNewlineAfterQualifier(); + } + @Override public void getBytecodeRange(BitSet values) { measureBytecode(values, lstOperands); 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 35a3c89b95..b3665eadf4 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java @@ -100,7 +100,12 @@ public List getAllExprents(List lst) { @Override public TextBuffer toJava(int indent) { - TextBuffer buf = condition.toJava(indent).enclose("if (", ")"); + TextBuffer buf = condition.toJava(indent); + buf.pushNewlineGroup(indent, 1); + buf.appendPossibleNewline(); + buf.enclose("if (", ")"); + buf.appendPossibleNewline("", true); + buf.popNewlineGroup(); buf.addStartBytecodeMapping(bytecode); return buf; } 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 2a9978fb69..e04c8f167a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -66,6 +66,7 @@ public class InvocationExprent extends Exprent { private List genericArgs = new ArrayList<>(); private Map genericsMap = new HashMap<>(); private boolean isInvocationInstance = false; + private boolean isQualifier = false; private boolean forceBoxing = false; private boolean forceUnboxing = false; private boolean isSyntheticNullCheck = false; @@ -515,17 +516,18 @@ public TextBuffer toJava(int indent) { String super_qualifier = null; boolean isInstanceThis = false; - buf.addBytecodeMapping(bytecode); - if (instance instanceof InvocationExprent) { ((InvocationExprent) instance).markUsingBoxingResult(); } + boolean pushedCallChainGroup = false; + if (isStatic || invocationTyp == INVOKE_DYNAMIC || invocationTyp == CONSTANT_DYNAMIC) { 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(lstParameters.get(0), descriptor.params[0], buf, indent, false, false, true, false); + buf.addBytecodeMapping(bytecode); return buf; } @@ -595,6 +597,7 @@ else if (instance != null) { if (isUnboxingCall() && !forceUnboxing) { // we don't print the unboxing call - no need to bother with the instance wrapping / casting + buf.addBytecodeMapping(bytecode); if (instance.type == Exprent.EXPRENT_FUNCTION) { FunctionExprent func = (FunctionExprent)instance; if (func.getFuncType() == FunctionExprent.FUNCTION_CAST && func.getLstOperands().get(1).type == Exprent.EXPRENT_CONST) { @@ -619,6 +622,12 @@ else if (instance != null) { return buf; } + instance.setIsQualifier(); + + if (!isQualifier) { + buf.pushNewlineGroup(indent, 1); + pushedCallChainGroup = true; + } TextBuffer res = instance.toJava(indent); boolean skippedCast = false; @@ -669,6 +678,9 @@ else if (JAVA_NIO_BUFFER.equals(descriptor.ret) && !JAVA_NIO_BUFFER.equals(right else { buf.append(res); } + if (instance.allowNewlineAfterQualifier()) { + buf.appendPossibleNewline(); + } } } } @@ -684,6 +696,8 @@ else if (JAVA_NIO_BUFFER.equals(descriptor.ret) && !JAVA_NIO_BUFFER.equals(right this.appendParameters(buf, genericArgs); } + buf.addBytecodeMapping(bytecode); + if (invocationTyp == INVOKE_DYNAMIC || invocationTyp == CONSTANT_DYNAMIC) { if (bootstrapMethod == null) { buf.append("<").append(name); @@ -712,6 +726,7 @@ else if (JAVA_NIO_BUFFER.equals(descriptor.ret) && !JAVA_NIO_BUFFER.equals(right throw new RuntimeException("Explicit invocation of " + CodeConstants.CLINIT_NAME); case TYP_INIT: + buf.addBytecodeMapping(bytecode); if (super_qualifier != null) { buf.append("super("); } @@ -727,6 +742,9 @@ else if (instance != null) { } buf.append(appendParamList(indent)).append(')'); + if (pushedCallChainGroup) { + buf.popNewlineGroup(); + } return buf; } @@ -750,6 +768,7 @@ private static void appendBootstrapArgument(TextBuffer buf, PooledConstant arg) public TextBuffer appendParamList(int indent) { TextBuffer buf = new TextBuffer(); + buf.pushNewlineGroup(indent, 1); List mask = null; boolean isEnum = false; if (functype == TYP_INIT) { @@ -881,6 +900,7 @@ else if (inv.isUnboxingCall() && !inv.shouldForceUnboxing()) { boolean firstParameter = true; + boolean pushedNestedGroup = false; for (int i = start; i < lstParameters.size(); i++) { if (mask == null || mask.get(i) == null) { TextBuffer buff = new TextBuffer(); @@ -924,7 +944,12 @@ else if (desc != null && desc.getSignature() != null && genericArgs.size() != 0) // the last "new Object[0]" in the vararg call is not printed if (buff.length() > 0) { if (!firstParameter) { - buf.append(", "); + buf.append(","); + buf.appendPossibleNewline(" "); + } else { + buf.appendPossibleNewline(); + buf.pushNewlineGroup(indent, 0); + pushedNestedGroup = true; } buf.append(buff); } @@ -932,7 +957,13 @@ else if (desc != null && desc.getSignature() != null && genericArgs.size() != 0) firstParameter = false; } } + if (pushedNestedGroup) { + buf.popNewlineGroup(); + } + + buf.appendPossibleNewline("", true); + buf.popNewlineGroup(); return buf; } @@ -986,6 +1017,11 @@ public void markUsingBoxingResult() { canIgnoreBoxing = false; } + @Override + public void setIsQualifier() { + isQualifier = true; + } + // TODO: move to CodeConstants ??? private static String getClassNameForPrimitiveType(int type) { switch (type) { 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 4a6e4a6424..868fe989ea 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -398,12 +398,22 @@ else if (!selfReference) { else if (directArrayInit) { VarType leftType = newType.decreaseArrayDim(); buf.append('{'); + if (!lstArrayElements.isEmpty()) { + buf.pushNewlineGroup(indent, 2); + buf.appendPossibleNewline(); + buf.pushNewlineGroup(indent, 0); + } for (int i = 0; i < lstArrayElements.size(); i++) { if (i > 0) { - buf.append(", "); + buf.append(",").appendPossibleNewline(" "); } ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false); } + if (!lstArrayElements.isEmpty()) { + buf.popNewlineGroup(); + buf.appendPossibleNewline("", true); + buf.popNewlineGroup(); + } buf.append('}'); } else if (newType.arrayDim == 0) { 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 7fdcefd5f4..cbc26915df 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -390,6 +390,11 @@ public boolean isVarReferenced(Exprent exp, VarExprent... whitelist) { return false; } + @Override + public boolean allowNewlineAfterQualifier() { + return false; + } + @Override public String toString() { return "VarExprent[" + index + ',' + version +"]"; 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 73b3c45818..1298e5fc49 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java @@ -96,21 +96,38 @@ public TextBuffer toJava(int indent) { case LOOP_DOWHILE: buf.appendIndent(indent).append("do {").appendLineSeparator(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false)); - buf.appendIndent(indent).append("} while(").append(conditionExprent.get(0).toJava(indent)).append(");").appendLineSeparator(); + buf.appendIndent(indent).append("} while("); + buf.pushNewlineGroup(indent, 1); + buf.appendPossibleNewline(); + buf.append(conditionExprent.get(0).toJava(indent)); + buf.appendPossibleNewline("", true); + buf.popNewlineGroup(); + buf.append(");").appendLineSeparator(); break; case LOOP_WHILE: - buf.appendIndent(indent).append("while(").append(conditionExprent.get(0).toJava(indent)).append(") {").appendLineSeparator(); + buf.appendIndent(indent).append("while("); + buf.pushNewlineGroup(indent, 1); + buf.appendPossibleNewline(); + buf.append(conditionExprent.get(0).toJava(indent)); + buf.appendPossibleNewline("", true); + buf.popNewlineGroup(); + buf.append(") {").appendLineSeparator(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false)); buf.appendIndent(indent).append("}").appendLineSeparator(); break; case LOOP_FOR: - buf.appendIndent(indent).append("for("); + buf.appendIndent(indent); + buf.pushNewlineGroup(indent, 1); + buf.append("for("); if (initExprent.get(0) != null) { buf.append(initExprent.get(0).toJava(indent)); } - buf.append("; ") - .append(conditionExprent.get(0).toJava(indent)).append("; ").append(incExprent.get(0).toJava(indent)).append(") {") - .appendLineSeparator(); + buf.append(";").appendPossibleNewline(" ") + .append(conditionExprent.get(0).toJava(indent)).append(";").appendPossibleNewline(" ") + .append(incExprent.get(0).toJava(indent)) + .appendPossibleNewline("", true); + buf.popNewlineGroup(); + buf.append(") {").appendLineSeparator(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, false)); buf.appendIndent(indent).append("}").appendLineSeparator(); break; diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index 134854ab51..d002bb4256 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -18,6 +18,10 @@ public class TextBuffer { private final String myLineSeparator = DecompilerContext.getNewLineSeparator(); private final String myIndent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING); + private final int myPreferredLineLength = DecompilerContext.getIntOption(IFernflowerPreferences.PREFERRED_LINE_LENGTH); + private final NewlineGroup myRootGroup = new NewlineGroup(null, 0, 0, 0); + private NewlineGroup myCurrentGroup = myRootGroup; + private boolean myHasReformatted = false; private final StringBuilder myStringBuilder; private Map myLineToOffsetMapping = null; private final Map myBytecodeOffsetMapping = new LinkedHashMap<>(); // bytecode offset -> offset in text @@ -61,6 +65,36 @@ public TextBuffer appendIndent(int length) { return this; } + public TextBuffer pushNewlineGroup(int baseIndent, int extraIndent) { + NewlineGroup group = new NewlineGroup(myCurrentGroup, myStringBuilder.length(), baseIndent, extraIndent); + myCurrentGroup.myChildren.add(group); + myCurrentGroup = group; + return this; + } + + public TextBuffer appendPossibleNewline() { + return appendPossibleNewline(""); + } + + public TextBuffer appendPossibleNewline(String alternative) { + return appendPossibleNewline(alternative, false); + } + + public TextBuffer appendPossibleNewline(String alternative, boolean dedent) { + myCurrentGroup.myReplacements.add(new NewlineGroup.Replacement(myStringBuilder.length(), alternative.length(), dedent)); + return append(alternative); + } + + public TextBuffer popNewlineGroup() { + if (myCurrentGroup == myRootGroup) { + throw new IllegalStateException("Cannot pop root group"); + } + assert myStringBuilder.length() >= myCurrentGroup.myStart; + myCurrentGroup.myLength = myStringBuilder.length() - myCurrentGroup.myStart; + myCurrentGroup = myCurrentGroup.myParent; + return this; + } + public TextBuffer prepend(String s) { myStringBuilder.insert(0, s); shiftMapping(s.length()); @@ -133,6 +167,103 @@ public Map, BytecodeMappingTracer> getTracers() { return tracers; } + private void reformatGroup(NewlineGroup group, List offsetMapping, int extraIndent) { + int offset = offsetMapping.get(group.myStart); + int actualStart = group.myStart + offset; + int lastNewline = myStringBuilder.lastIndexOf(myLineSeparator, actualStart); + int nextNewline = myStringBuilder.indexOf(myLineSeparator, actualStart); + int firstGroupEnd = nextNewline == -1 ? actualStart + group.myLength : Math.min(nextNewline, actualStart + group.myLength); + int groupEndWithoutNewlines = lastNewline == -1 ? firstGroupEnd : firstGroupEnd - lastNewline; + while (nextNewline != -1 && nextNewline <= actualStart + group.myLength) { + int lineStart = nextNewline; + int lineEnd = nextNewline = myStringBuilder.indexOf(myLineSeparator, nextNewline + 1); + if (lineEnd == -1 || lineEnd > actualStart + group.myLength) { + lineEnd = actualStart + group.myLength; + } + int lineLength = extraIndent + lineEnd - lineStart - myLineSeparator.length(); + if (lineLength > groupEndWithoutNewlines) { + groupEndWithoutNewlines = lineLength; + } + } + boolean addNewLines = groupEndWithoutNewlines > myPreferredLineLength; + + int originalExtraIndent = extraIndent; + if (addNewLines && !group.myReplacements.isEmpty()) { + extraIndent += group.myExtraIndent; + } + + int childrenIndex = 0; + int replacementIndex = 0; + for (int pos = group.myStart; pos <= group.myStart + group.myLength; pos++) { + if (pos != group.myStart) { + offsetMapping.add(offset); + } + assert offsetMapping.size() == pos + 1; + + // add extra indent after newlines + if (pos + offset + myLineSeparator.length() < myStringBuilder.length() && myStringBuilder.substring(pos + offset, pos + offset + myLineSeparator.length()).equals(myLineSeparator)) { + for (int i = 0; i < extraIndent; i++) { + myStringBuilder.insert(pos + offset + myLineSeparator.length(), myIndent); + } + offset += myIndent.length() * extraIndent; + } + + boolean anotherPass = true; + while (anotherPass) { + anotherPass = false; + + // replace replaceables with newlines + if (addNewLines && replacementIndex < group.myReplacements.size() && pos == group.myReplacements.get(replacementIndex).myStart) { + NewlineGroup.Replacement replacement = group.myReplacements.get(replacementIndex); + myStringBuilder.replace(pos + offset, pos + offset + replacement.myLength, myLineSeparator); + if (replacement.myDedent) { + extraIndent = originalExtraIndent; + } + for (int i = 0; i < group.myBaseIndent + extraIndent; i++) { + myStringBuilder.insert(pos + offset + myLineSeparator.length(), myIndent); + } + offset += myIndent.length() * (group.myBaseIndent + extraIndent) + myLineSeparator.length() - replacement.myLength; + replacementIndex++; + anotherPass = true; + } + offsetMapping.set(offsetMapping.size() - 1, offset); + + // recursively iterate through child groups + int currentPos = pos; + if (childrenIndex < group.myChildren.size() && group.myChildren.get(childrenIndex).myStart == currentPos) { + NewlineGroup child = group.myChildren.get(childrenIndex); + reformatGroup(child, offsetMapping, extraIndent); + offset = offsetMapping.get(offsetMapping.size() - 1); + pos += child.myLength; + childrenIndex++; + anotherPass = true; + } + } + } + offsetMapping.set(offsetMapping.size() - 1, offset); + } + + + public void reformat() { + if (myCurrentGroup != myRootGroup) { + throw new IllegalStateException("Cannot reformat while in a group"); + } + if (myHasReformatted) { + throw new IllegalStateException("Cannot reformat twice"); + } + myHasReformatted = true; + + //myRootGroup.dump(""); + + myRootGroup.myLength = myStringBuilder.length(); + + List offsetMapping = new ArrayList<>(myStringBuilder.length()); + offsetMapping.add(0); + reformatGroup(myRootGroup, offsetMapping, 0); + + myBytecodeOffsetMapping.replaceAll((key, value) -> value + offsetMapping.get(value)); + } + @Override public String toString() { String original = myStringBuilder.toString(); @@ -241,9 +372,23 @@ public void setLength(int position) { } myLineToOffsetMapping = newMap; } + myRootGroup.truncate(position); + assert currentGroupExists(); + } + + private boolean currentGroupExists() { + for (NewlineGroup group = myCurrentGroup; group != myRootGroup; group = group.myParent) { + if (!group.myParent.myChildren.contains(group)) { + return false; + } + } + return true; } public TextBuffer append(TextBuffer buffer, String className, String methodKey) { + if (buffer.myCurrentGroup != buffer.myRootGroup) { + throw new IllegalArgumentException("Can't append buffer with non-root group"); + } if (buffer.myLineToOffsetMapping != null && !buffer.myLineToOffsetMapping.isEmpty()) { checkMapCreated(); for (Map.Entry entry : buffer.myLineToOffsetMapping.entrySet()) { @@ -256,6 +401,10 @@ public TextBuffer append(TextBuffer buffer, String className, String methodKey) } myBytecodeOffsetMapping.putIfAbsent(key, value + myStringBuilder.length()); }); + NewlineGroup otherRoot = buffer.myRootGroup.copy(); + otherRoot.shift(myStringBuilder.length()); + myCurrentGroup.myReplacements.addAll(otherRoot.myReplacements); + myCurrentGroup.myChildren.addAll(otherRoot.myChildren); myStringBuilder.append(buffer.myStringBuilder); return this; } @@ -279,6 +428,7 @@ private void shiftMapping(int shiftOffset) { myLineToOffsetMapping = newMap; } myBytecodeOffsetMapping.replaceAll((key, value) -> value + shiftOffset); + myRootGroup.shift(shiftOffset); } private void checkMapCreated() { @@ -379,4 +529,75 @@ public String toString() { return myClass + ":" + myMethod + ":" + myBytecodeOffset; } } + + private static final class NewlineGroup { + final NewlineGroup myParent; + int myStart; + int myLength; + final int myBaseIndent; + final int myExtraIndent; + final List myChildren = new ArrayList<>(); + final List myReplacements = new ArrayList<>(); + + NewlineGroup(NewlineGroup parent, int start, int baseIndent, int extraIndent) { + this.myParent = parent; + this.myStart = start; + this.myBaseIndent = baseIndent; + this.myExtraIndent = extraIndent; + } + + void shift(int amount) { + myStart += amount; + for (Replacement replacement : myReplacements) { + replacement.myStart += amount; + } + for (NewlineGroup child : myChildren) { + child.shift(amount); + } + } + + void truncate(int stringLength) { + if (myStart + myLength > stringLength) { + myLength = stringLength - myStart; + } + for (Iterator itr = myChildren.iterator(); itr.hasNext(); ) { + NewlineGroup child = itr.next(); + if (child.myStart <= stringLength) { + child.truncate(stringLength); + } else { + itr.remove(); + } + } + myReplacements.removeIf(r -> r.myStart > stringLength); + } + + void dump(String indent) { + System.out.println(indent + "group " + myStart + "-" + (myStart + myLength) + ": " + myReplacements.size() + " replacements"); + for (NewlineGroup child : myChildren) { + child.dump(indent + " "); + } + } + + NewlineGroup copy() { + NewlineGroup copy = new NewlineGroup(myParent, myStart, myBaseIndent, myExtraIndent); + copy.myLength = myLength; + for (NewlineGroup child : myChildren) { + copy.myChildren.add(child.copy()); + } + copy.myReplacements.addAll(myReplacements); + return copy; + } + + private static class Replacement { + int myStart; + final int myLength; + final boolean myDedent; + + Replacement(int start, int length, boolean dedent) { + this.myStart = start; + this.myLength = length; + this.myDedent = dedent; + } + } + } } \ No newline at end of file diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index e4d23e7fa7..d90f3a9101 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -14,8 +14,7 @@ protected void registerAll() { IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR, "0", IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", - IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "0", - IFernflowerPreferences.INLINE_SIMPLE_LAMBDAS, "0" + IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "0" ); registerSet("Entire Classpath", this::registerEntireClassPath, IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", @@ -23,8 +22,7 @@ protected void registerAll() { IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR, "0", IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", - IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "1", - IFernflowerPreferences.INLINE_SIMPLE_LAMBDAS, "0" + IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "1" ); registerSet("Java Runtime", this::registerJavaRuntime, IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", @@ -32,8 +30,7 @@ protected void registerAll() { IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR, "0", IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", - IFernflowerPreferences.INCLUDE_JAVA_RUNTIME, "1", - IFernflowerPreferences.INLINE_SIMPLE_LAMBDAS, "0" + IFernflowerPreferences.INCLUDE_JAVA_RUNTIME, "1" ); registerSet("Literals", this::registerLiterals, IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", @@ -50,7 +47,6 @@ protected void registerAll() { IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "0", - IFernflowerPreferences.INLINE_SIMPLE_LAMBDAS, "0", IFernflowerPreferences.PATTERN_MATCHING, "1" ); registerSet("Ternary Constant Simplification", this::registerTernaryConstantSimplification, @@ -86,7 +82,6 @@ protected void registerAll() { IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "0", - IFernflowerPreferences.INLINE_SIMPLE_LAMBDAS, "0", IFernflowerPreferences.EXPERIMENTAL_TRY_LOOP_FIX, "1" ); } @@ -180,6 +175,7 @@ private void registerDefault() { register(JAVA_16, "TestRecordVararg"); register(JAVA_16, "TestRecordGenericVararg"); register(JAVA_16, "TestRecordAnno"); + register(JAVA_16, "TestRecordBig"); // TODO: The (double) in front of the (int) should be removed register(JAVA_8, "TestMultiCast"); // TODO: The ternary here needs to be removed @@ -252,6 +248,9 @@ private void registerDefault() { register(JAVA_16, "TestRecordMixup"); register(JAVA_8, "TestMultiAssignmentInStaticBlock"); register(JAVA_8, "TestNextGaussian"); + register(JAVA_8, "TestLongMethodDeclaration"); + register(JAVA_8, "TestLongMethodInvocation"); + register(JAVA_8, "TestBinaryOperationWrapping"); register(JAVA_8, "TestLoopBreak"); register(JAVA_8, "TestLoopBreak2"); register(JAVA_8, "TestSimpleWhile"); diff --git a/testData/kt25937/kt/Kt25937Kt.java b/testData/kt25937/kt/Kt25937Kt.java index 4855c45d9f..aaa4570696 100644 --- a/testData/kt25937/kt/Kt25937Kt.java +++ b/testData/kt25937/kt/Kt25937Kt.java @@ -15,7 +15,9 @@ d2 = {"callSuspendBlock", "", "block", "Lkotlin/Function1;", "Lkotlin/coroutines/Continuation;", "", "", "(Lkotlin/jvm/functions/Function1;)I", "callSuspendBlockGood", "kotlinx-test"} ) public final class Kt25937Kt { - public static final int callSuspendBlock(@NotNull Function1, ? extends Object> block) { + public static final int callSuspendBlock( + @NotNull Function1, ? extends Object> block + ) { Intrinsics.checkParameterIsNotNull(block, "block"); return 1; } diff --git a/testData/kt25937/kt/Kt25937_1Kt.java b/testData/kt25937/kt/Kt25937_1Kt.java index ea79e6ed53..d8dcae2d7c 100644 --- a/testData/kt25937/kt/Kt25937_1Kt.java +++ b/testData/kt25937/kt/Kt25937_1Kt.java @@ -19,30 +19,32 @@ ) public final class Kt25937_1Kt { public static final int some1() { - return Kt25937Kt.callSuspendBlock((Function1)(new Function1, Object>((Continuation)null) { - int label; - - @Nullable - public final Object invokeSuspend(@NotNull Object $result) { - Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); - switch(this.label) { - case 0: - ResultKt.throwOnFailure($result); - return Unit.INSTANCE; - default: - throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); + return Kt25937Kt.callSuspendBlock( + (Function1)(new Function1, Object>((Continuation)null) { + int label; + + @Nullable + public final Object invokeSuspend(@NotNull Object $result) { + Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); + switch(this.label) { + case 0: + ResultKt.throwOnFailure($result); + return Unit.INSTANCE; + default: + throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); + } } - } - - @NotNull - public final Continuation create(@NotNull Continuation completion) { - Intrinsics.checkParameterIsNotNull(completion, "completion"); - return new (completion); - } - - public final Object invoke(Object var1) { - return (()this.create((Continuation)var1)).invokeSuspend(Unit.INSTANCE); - } - })); + + @NotNull + public final Continuation create(@NotNull Continuation completion) { + Intrinsics.checkParameterIsNotNull(completion, "completion"); + return new (completion); + } + + public final Object invoke(Object var1) { + return (()this.create((Continuation)var1)).invokeSuspend(Unit.INSTANCE); + } + }) + ); } } diff --git a/testData/results/pkg/TestAnonymousClass.dec b/testData/results/pkg/TestAnonymousClass.dec index 46f16040d4..e02c713987 100644 --- a/testData/results/pkg/TestAnonymousClass.dec +++ b/testData/results/pkg/TestAnonymousClass.dec @@ -22,27 +22,31 @@ public abstract class TestAnonymousClass { int b = 5;// 62 }// 63 }; - private final TestAnonymousClass.InnerRecursive y = new TestAnonymousClass.InnerRecursive(new TestAnonymousClass.InnerRecursive((TestAnonymousClass.InnerRecursive)null) { - @Override - void foo() { - int a = 5;// 83 - int b = 5;// 84 - int g = 5;// 85 - }// 86 - }) { + private final TestAnonymousClass.InnerRecursive y = new TestAnonymousClass.InnerRecursive( + new TestAnonymousClass.InnerRecursive((TestAnonymousClass.InnerRecursive)null) { + @Override + void foo() { + int a = 5;// 83 + int b = 5;// 84 + int g = 5;// 85 + }// 86 + } + ) { int v = 5; int t = 5; int j = 5; int o = 5; }; - private final TestAnonymousClass.InnerRecursive x = new TestAnonymousClass.InnerRecursive(new TestAnonymousClass.InnerRecursive((TestAnonymousClass.InnerRecursive)null) { - @Override - void foo() { - int a = 5;// 98 - int b = 5;// 99 - int g = 5;// 100 - }// 101 - }) { + private final TestAnonymousClass.InnerRecursive x = new TestAnonymousClass.InnerRecursive( + new TestAnonymousClass.InnerRecursive((TestAnonymousClass.InnerRecursive)null) { + @Override + void foo() { + int a = 5;// 98 + int b = 5;// 99 + int g = 5;// 100 + }// 101 + } + ) { int v = 5; int t = 5; int j = 5; @@ -67,11 +71,11 @@ public abstract class TestAnonymousClass { }// 23 void bar() { - (()(new Object() {// 30 + (()(new Object() { public void foo(String s) { System.out.println(s);// 28 }// 29 - })).foo("Hello world");// 26 + })).foo("Hello world");// 26 30 }// 31 void boo() { @@ -140,161 +144,161 @@ class 'pkg/TestAnonymousClass$5' { class 'pkg/TestAnonymousClass$6' { method 'foo ()V' { - 0 27 - 1 27 - 2 28 - 3 28 - 4 29 - 5 29 - 6 30 + 0 28 + 1 28 + 2 29 + 3 29 + 4 30 + 5 30 + 6 31 } } class 'pkg/TestAnonymousClass$8' { method 'foo ()V' { - 0 40 - 1 40 - 2 41 - 3 41 - 4 42 - 5 42 - 6 43 + 0 43 + 1 43 + 2 44 + 3 44 + 4 45 + 5 45 + 6 46 } } class 'pkg/TestAnonymousClass' { method 'foo (I)V' { - 0 52 - 1 52 - c 53 - d 60 - e 60 - f 60 - 10 60 - 11 60 - 12 60 - 16 62 - 17 62 - 18 63 - 19 63 - 1a 63 - 1b 63 - 1c 63 - 1f 66 + 0 56 + 1 56 + c 57 + d 64 + e 64 + f 64 + 10 64 + 11 64 + 12 64 + 16 66 + 17 66 + 18 67 + 19 67 + 1a 67 + 1b 67 + 1c 67 + 1f 70 } method 'bar ()V' { - 8 73 - 9 73 - a 69 - b 69 - c 69 - d 74 + 8 77 + 9 77 + a 77 + b 77 + c 77 + d 78 } method 'boo ()V' { - 0 77 - 1 77 - 2 78 - } - - method 'zoo ()V' { 0 81 1 81 2 82 } + + method 'zoo ()V' { + 0 85 + 1 85 + 2 86 + } } class 'pkg/TestAnonymousClass$1' { method 'foo ()V' { - 0 56 - 1 56 - 2 57 - 3 57 - 4 58 + 0 60 + 1 60 + 2 61 + 3 61 + 4 62 } } class 'pkg/TestAnonymousClass$2' { method 'foo (Ljava/lang/String;)V' { - 0 71 - 1 71 - 2 71 - 3 71 - 4 71 - 5 71 - 6 71 - 7 72 + 0 75 + 1 75 + 2 75 + 3 75 + 4 75 + 5 75 + 6 75 + 7 76 } } class 'pkg/TestAnonymousClass$Inner$1' { method 'run ()V' { - 0 92 - 1 92 - 2 93 - 3 93 - 4 94 + 0 96 + 1 96 + 2 97 + 3 97 + 4 98 } } class 'pkg/TestAnonymousClass$InnerRecursive' { method ' (Lpkg/TestAnonymousClass$InnerRecursive;)V' { - 4 102 - 5 102 - 6 102 - 7 102 - 8 102 - 9 103 + 4 106 + 5 106 + 6 106 + 7 106 + 8 106 + 9 107 } method 'foo ()V' { - 0 106 + 0 110 } } Lines mapping: -10 <-> 53 -11 <-> 54 -13 <-> 57 -14 <-> 58 -15 <-> 59 -17 <-> 61 -20 <-> 63 -21 <-> 64 -23 <-> 67 -26 <-> 74 -28 <-> 72 -29 <-> 73 -30 <-> 70 -31 <-> 75 +10 <-> 57 +11 <-> 58 +13 <-> 61 +14 <-> 62 +15 <-> 63 +17 <-> 65 +20 <-> 67 +21 <-> 68 +23 <-> 71 +26 <-> 78 +28 <-> 76 +29 <-> 77 +30 <-> 78 +31 <-> 79 36 <-> 7 37 <-> 8 38 <-> 9 -43 <-> 78 -44 <-> 79 -47 <-> 82 -48 <-> 83 +43 <-> 82 +44 <-> 83 +47 <-> 86 +48 <-> 87 53 <-> 14 54 <-> 15 55 <-> 16 61 <-> 21 62 <-> 22 63 <-> 23 -74 <-> 93 -75 <-> 94 -76 <-> 95 -83 <-> 28 -84 <-> 29 -85 <-> 30 -86 <-> 31 -98 <-> 41 -99 <-> 42 -100 <-> 43 -101 <-> 44 -113 <-> 103 -114 <-> 104 -118 <-> 107 +74 <-> 97 +75 <-> 98 +76 <-> 99 +83 <-> 29 +84 <-> 30 +85 <-> 31 +86 <-> 32 +98 <-> 44 +99 <-> 45 +100 <-> 46 +101 <-> 47 +113 <-> 107 +114 <-> 108 +118 <-> 111 Not mapped: 18 112 diff --git a/testData/results/pkg/TestAnonymousClassConstructor.dec b/testData/results/pkg/TestAnonymousClassConstructor.dec index e0ab2c8e78..cdc5aeba47 100644 --- a/testData/results/pkg/TestAnonymousClassConstructor.dec +++ b/testData/results/pkg/TestAnonymousClassConstructor.dec @@ -2,7 +2,9 @@ package pkg; class TestAnonymousClassConstructor { void innerPrivateString() { - TestAnonymousClassConstructor.InnerPrivateString var10001 = new TestAnonymousClassConstructor.InnerPrivateString("text") {// 5 + TestAnonymousClassConstructor.InnerPrivateString var10001 = new TestAnonymousClassConstructor.InnerPrivateString( + "text"// 5 + ) { }; }// 6 @@ -12,27 +14,37 @@ class TestAnonymousClassConstructor { }// 10 void innerStaticPrivateString() { - TestAnonymousClassConstructor.InnerStaticPrivateString var10001 = new TestAnonymousClassConstructor.InnerStaticPrivateString("text") {// 13 + TestAnonymousClassConstructor.InnerStaticPrivateString var10001 = new TestAnonymousClassConstructor.InnerStaticPrivateString( + "text"// 13 + ) { }; }// 14 void innerStaticPrivate() { - TestAnonymousClassConstructor.InnerStaticPrivate var10001 = new TestAnonymousClassConstructor.InnerStaticPrivate(3L, 4) {// 17 + TestAnonymousClassConstructor.InnerStaticPrivate var10001 = new TestAnonymousClassConstructor.InnerStaticPrivate( + 3L, 4// 17 + ) { }; }// 18 static void innerStaticPrivateStringStatic() { - TestAnonymousClassConstructor.InnerStaticPrivateString var10001 = new TestAnonymousClassConstructor.InnerStaticPrivateString("text") {// 21 + TestAnonymousClassConstructor.InnerStaticPrivateString var10001 = new TestAnonymousClassConstructor.InnerStaticPrivateString( + "text"// 21 + ) { }; }// 22 static void innerStaticPrivateStatic() { - TestAnonymousClassConstructor.InnerStaticPrivate var10001 = new TestAnonymousClassConstructor.InnerStaticPrivate(3L, 4) {// 25 + TestAnonymousClassConstructor.InnerStaticPrivate var10001 = new TestAnonymousClassConstructor.InnerStaticPrivate( + 3L, 4// 25 + ) { }; }// 26 void innerPublicString() { - TestAnonymousClassConstructor.InnerPublicString var10001 = new TestAnonymousClassConstructor.InnerPublicString("text") {// 29 + TestAnonymousClassConstructor.InnerPublicString var10001 = new TestAnonymousClassConstructor.InnerPublicString( + "text"// 29 + ) { }; }// 30 @@ -42,22 +54,30 @@ class TestAnonymousClassConstructor { }// 34 void innerStaticPublicString() { - TestAnonymousClassConstructor.InnerStaticPublicString var10001 = new TestAnonymousClassConstructor.InnerStaticPublicString("text") {// 37 + TestAnonymousClassConstructor.InnerStaticPublicString var10001 = new TestAnonymousClassConstructor.InnerStaticPublicString( + "text"// 37 + ) { }; }// 38 void innerStaticPublic() { - TestAnonymousClassConstructor.InnerStaticPublic var10001 = new TestAnonymousClassConstructor.InnerStaticPublic(3L, 4) {// 41 + TestAnonymousClassConstructor.InnerStaticPublic var10001 = new TestAnonymousClassConstructor.InnerStaticPublic( + 3L, 4// 41 + ) { }; }// 42 static void innerStaticPublicStringStatic() { - TestAnonymousClassConstructor.InnerStaticPublicString var10001 = new TestAnonymousClassConstructor.InnerStaticPublicString("text") {// 45 + TestAnonymousClassConstructor.InnerStaticPublicString var10001 = new TestAnonymousClassConstructor.InnerStaticPublicString( + "text"// 45 + ) { }; }// 46 static void innerStaticPublicStatic() { - TestAnonymousClassConstructor.InnerStaticPublic var10001 = new TestAnonymousClassConstructor.InnerStaticPublic(3L, 4) {// 49 + TestAnonymousClassConstructor.InnerStaticPublic var10001 = new TestAnonymousClassConstructor.InnerStaticPublic( + 3L, 4// 49 + ) { }; }// 50 @@ -116,255 +136,255 @@ class TestAnonymousClassConstructor { class 'pkg/TestAnonymousClassConstructor' { method 'innerPrivateString ()V' { - 5 4 - 6 4 - b 6 + 5 5 + 6 5 + b 8 } method 'innerPrivate ()V' { - 5 9 - 6 9 - 7 9 - 8 9 - d 11 + 5 11 + 6 11 + 7 11 + 8 11 + d 13 } method 'innerStaticPrivateString ()V' { - 5 14 - 6 14 - b 16 + 5 17 + 6 17 + b 20 } method 'innerStaticPrivate ()V' { - 5 19 - 6 19 - 7 19 - 8 19 - d 21 + 5 24 + 6 24 + 7 24 + 8 24 + d 27 } method 'innerStaticPrivateStringStatic ()V' { - 4 24 - 5 24 - a 26 + 4 31 + 5 31 + a 34 } method 'innerStaticPrivateStatic ()V' { - 4 29 - 5 29 - 6 29 - 7 29 - c 31 + 4 38 + 5 38 + 6 38 + 7 38 + c 41 } method 'innerPublicString ()V' { - 5 34 - 6 34 - b 36 + 5 45 + 6 45 + b 48 } method 'innerPublic ()V' { - 5 39 - 6 39 - 7 39 - 8 39 - d 41 + 5 51 + 6 51 + 7 51 + 8 51 + d 53 } method 'innerStaticPublicString ()V' { - 5 44 - 6 44 - b 46 + 5 57 + 6 57 + b 60 } method 'innerStaticPublic ()V' { - 5 49 - 6 49 - 7 49 - 8 49 - d 51 + 5 64 + 6 64 + 7 64 + 8 64 + d 67 } method 'innerStaticPublicStringStatic ()V' { - 4 54 - 5 54 - a 56 + 4 71 + 5 71 + a 74 } method 'innerStaticPublicStatic ()V' { - 4 59 - 5 59 - 6 59 - 7 59 - c 61 + 4 78 + 5 78 + 6 78 + 7 78 + c 81 } 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 + 0 84 + 1 84 + 2 84 + a 84 + b 84 + f 84 + 13 84 + 14 84 + 15 84 + 16 84 + 17 84 + 18 84 + 19 85 } } 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 + 10 89 + 14 89 + 15 89 + 19 89 + 1a 89 + 1e 89 + 1f 89 + 20 89 + 21 89 + 22 89 + 23 89 + 24 90 } } class 'pkg/TestAnonymousClassConstructor$InnerPrivateString' { method ' (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' { - 9 75 - a 75 - b 75 - c 75 - d 76 + 9 95 + a 95 + b 95 + c 95 + d 96 } } 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 + 10 101 + 14 101 + 15 101 + 19 101 + 1a 101 + 1e 101 + 1f 101 + 20 101 + 21 101 + 22 101 + 23 101 + 24 102 } } class 'pkg/TestAnonymousClassConstructor$InnerPublicString' { method ' (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' { - 9 87 - a 87 - b 87 - c 87 - d 88 + 9 107 + a 107 + b 107 + c 107 + d 108 } } 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 + b 113 + f 113 + 10 113 + 14 113 + 18 113 + 19 113 + 1a 113 + 1b 113 + 1c 113 + 1d 113 + 1e 114 } } class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivateString' { method ' (Ljava/lang/String;)V' { - 4 99 - 5 99 - 6 99 - 7 99 - 8 100 + 4 119 + 5 119 + 6 119 + 7 119 + 8 120 } } 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 + b 125 + f 125 + 10 125 + 14 125 + 18 125 + 19 125 + 1a 125 + 1b 125 + 1c 125 + 1d 125 + 1e 126 } } class 'pkg/TestAnonymousClassConstructor$InnerStaticPublicString' { method ' (Ljava/lang/String;)V' { - 4 111 - 5 111 - 6 111 - 7 111 - 8 112 + 4 131 + 5 131 + 6 131 + 7 131 + 8 132 } } Lines mapping: -5 <-> 5 -6 <-> 7 -9 <-> 10 -10 <-> 12 -13 <-> 15 -14 <-> 17 -17 <-> 20 -18 <-> 22 -21 <-> 25 -22 <-> 27 -25 <-> 30 -26 <-> 32 -29 <-> 35 -30 <-> 37 -33 <-> 40 -34 <-> 42 -37 <-> 45 -38 <-> 47 -41 <-> 50 -42 <-> 52 -45 <-> 55 -46 <-> 57 -49 <-> 60 -50 <-> 62 -53 <-> 65 -54 <-> 66 -58 <-> 76 -59 <-> 77 -64 <-> 70 -65 <-> 71 -70 <-> 100 -71 <-> 101 -76 <-> 94 -77 <-> 95 -82 <-> 88 -83 <-> 89 -88 <-> 82 -89 <-> 83 -94 <-> 112 -95 <-> 113 -100 <-> 106 -101 <-> 107 +5 <-> 6 +6 <-> 9 +9 <-> 12 +10 <-> 14 +13 <-> 18 +14 <-> 21 +17 <-> 25 +18 <-> 28 +21 <-> 32 +22 <-> 35 +25 <-> 39 +26 <-> 42 +29 <-> 46 +30 <-> 49 +33 <-> 52 +34 <-> 54 +37 <-> 58 +38 <-> 61 +41 <-> 65 +42 <-> 68 +45 <-> 72 +46 <-> 75 +49 <-> 79 +50 <-> 82 +53 <-> 85 +54 <-> 86 +58 <-> 96 +59 <-> 97 +64 <-> 90 +65 <-> 91 +70 <-> 120 +71 <-> 121 +76 <-> 114 +77 <-> 115 +82 <-> 108 +83 <-> 109 +88 <-> 102 +89 <-> 103 +94 <-> 132 +95 <-> 133 +100 <-> 126 +101 <-> 127 Not mapped: 57 63 diff --git a/testData/results/pkg/TestBinaryOperationWrapping.dec b/testData/results/pkg/TestBinaryOperationWrapping.dec new file mode 100644 index 0000000000..c21bfe4cde --- /dev/null +++ b/testData/results/pkg/TestBinaryOperationWrapping.dec @@ -0,0 +1,148 @@ +package pkg; + +public class TestBinaryOperationWrapping { + public void testStringConcatenation(String longVariableName) { + System.out// 5 + .println( + "This is a very very very very very very very very very very very very very very very long string" + + longVariableName + + longVariableName + + longVariableName + + longVariableName + + longVariableName + ); + }// 9 + + public void testBooleanOperation( + boolean a, + boolean b, + boolean c, + boolean d, + boolean e, + boolean f, + boolean g, + boolean h, + boolean i, + boolean j, + boolean k, + boolean l, + boolean m, + boolean n, + boolean o, + boolean p, + boolean q, + boolean r, + boolean s, + boolean t, + boolean u, + boolean v, + boolean w, + boolean x, + boolean y, + boolean z + ) { + System.out// 12 + .println( + a && b || + c && d || + e && f || + g && h || + i && j || + k && l || + m && n || + o && p || + q && r || + s && t || + u && v || + w && x || + y && z + ); + }// 13 +} + +class 'pkg/TestBinaryOperationWrapping' { + method 'testStringConcatenation (Ljava/lang/String;)V' { + 0 4 + 1 4 + 2 4 + a 6 + b 6 + f 7 + 13 8 + 17 9 + 1b 10 + 1f 11 + 23 6 + 24 6 + 25 6 + 26 5 + 27 5 + 28 5 + 29 13 + } + + method 'testBooleanOperation (ZZZZZZZZZZZZZZZZZZZZZZZZZZ)V' { + 0 43 + 1 43 + 2 43 + 3 45 + 7 45 + b 46 + f 46 + 10 46 + 14 47 + 15 47 + 19 47 + 1a 47 + 1e 48 + 1f 48 + 23 48 + 24 48 + 28 49 + 29 49 + 2d 49 + 2e 49 + 32 50 + 33 50 + 37 50 + 38 50 + 3c 51 + 3d 51 + 41 51 + 42 51 + 46 52 + 47 52 + 4b 52 + 4c 52 + 50 53 + 51 53 + 55 53 + 56 53 + 5a 54 + 5b 54 + 5f 54 + 60 54 + 64 55 + 65 55 + 69 55 + 6a 55 + 6e 56 + 6f 56 + 73 56 + 74 56 + 78 57 + 79 57 + 7d 57 + 7e 57 + 87 44 + 88 44 + 89 44 + 8a 59 + } +} + +Lines mapping: +5 <-> 5 +9 <-> 14 +12 <-> 44 +13 <-> 60 diff --git a/testData/results/pkg/TestClassLambda.dec b/testData/results/pkg/TestClassLambda.dec index ace7f3a6bd..c48799b2f5 100644 --- a/testData/results/pkg/TestClassLambda.dec +++ b/testData/results/pkg/TestClassLambda.dec @@ -22,18 +22,12 @@ public class TestClassLambda { public void testLambda1() { int a = (int)Math.random();// 39 - Runnable r1 = () -> { - System.out.println("hello1" + a);// 40 - }; - Runnable r2 = () -> { - System.out.println("hello2" + a);// 41 - }; + Runnable r1 = () -> System.out.println("hello1" + a);// 40 + Runnable r2 = () -> System.out.println("hello2" + a);// 41 }// 42 public void testLambda2() { - reduce((left, right) -> { - return Math.max(left, right);// 45 - }); + reduce((left, right) -> Math.max(left, right));// 45 }// 46 public void testLambda3() { @@ -53,9 +47,7 @@ public class TestClassLambda { List list = new ArrayList();// 62 int bottom = list.size() * 2;// 63 int top = list.size() * 5;// 64 - list.removeIf(s -> { - return bottom >= s.length() && s.length() <= top;// 65 - }); + list.removeIf(s -> bottom >= s.length() && s.length() <= top);// 65 }// 66 public static void testLambda7(Annotation[] annotations) { @@ -77,9 +69,7 @@ public class TestClassLambda { public void nestedLambdas() { int a = 5;// 85 Runnable r1 = () -> {// 86 - Runnable r2 = () -> { - System.out.println("hello2" + a);// 87 - }; + Runnable r2 = () -> System.out.println("hello2" + a);// 87 System.out.println("hello1" + a);// 88 };// 89 }// 90 @@ -167,11 +157,27 @@ class 'pkg/TestClassLambda' { 3 23 4 23 b 24 - 12 27 - 13 30 + 12 25 + 13 26 } method 'lambda$testLambda1$1 (I)V' { + 0 24 + 1 24 + 2 24 + a 24 + b 24 + f 24 + 13 24 + 14 24 + 15 24 + 16 24 + 17 24 + 18 24 + 19 24 + } + + method 'lambda$testLambda1$2 (I)V' { 0 25 1 25 2 25 @@ -184,185 +190,169 @@ class 'pkg/TestClassLambda' { 16 25 17 25 18 25 - 19 26 - } - - 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 + 19 25 } method 'testLambda2 ()V' { - 5 33 - 6 33 - 7 33 - 9 36 + 5 29 + 6 29 + 7 29 + 9 30 } method 'lambda$testLambda2$3 (II)I' { - 0 34 - 1 34 - 2 34 - 3 34 - 4 34 - 5 34 + 0 29 + 1 29 + 2 29 + 3 29 + 4 29 + 5 29 } method 'testLambda3 ()V' { - 5 39 - 6 39 - 7 39 - 9 40 + 5 33 + 6 33 + 7 33 + 9 34 } method 'testLambda4 ()V' { - 5 43 - 6 43 - 7 43 - 9 44 + 5 37 + 6 37 + 7 37 + 9 38 } method 'testLambda5 ()V' { - 0 47 - 1 47 - 2 47 - 3 48 - e 48 - f 48 - 10 48 - 12 49 + 0 41 + 1 41 + 2 41 + 3 42 + e 42 + f 42 + 10 42 + 12 43 } method 'testLambda6 ()V' { - 7 52 - 8 53 + 7 46 + 8 47 + 9 47 + a 47 + b 47 + c 47 + d 47 + e 47 + f 47 + 10 47 + 11 48 + 12 48 + 13 48 + 14 48 + 15 48 + 16 48 + 17 48 + 18 48 + 19 48 + 1a 49 + 22 49 + 23 49 + 24 49 + 25 49 + 26 49 + 28 50 + } + + method 'lambda$testLambda6$4 (IILjava/lang/String;)Z' { + 0 49 + 1 49 + 2 49 + 3 49 + 4 49 + 5 49 + 8 49 + 9 49 + a 49 + b 49 + c 49 + d 49 + 15 49 + } + + method 'testLambda7 ([Ljava/lang/annotation/Annotation;)V' { + 0 53 + 1 53 + 2 53 + 3 53 9 53 a 53 b 53 c 53 d 53 - e 53 - f 53 - 10 53 - 11 54 - 12 54 - 13 54 - 14 54 - 15 54 - 16 54 - 17 54 - 18 54 - 19 54 - 1a 55 - 22 55 - 23 55 - 24 55 - 25 55 - 26 55 - 28 58 + f 54 } - method 'lambda$testLambda6$4 (IILjava/lang/String;)Z' { - 0 56 - 1 56 - 2 56 - 3 56 - 4 56 - 5 56 - 8 56 - 9 56 - a 56 - b 56 - c 56 - d 56 - 15 56 + method 'reduce (Ljava/util/function/IntBinaryOperator;)Ljava/util/OptionalInt;' { + 0 57 + 1 57 } - method 'testLambda7 ([Ljava/lang/annotation/Annotation;)V' { + method 'function (Ljava/util/function/Supplier;)Ljava/lang/String;' { 0 61 1 61 2 61 3 61 + 4 61 + 5 61 + 6 61 + 7 61 + 8 61 9 61 - a 61 - b 61 - c 61 - d 61 - f 62 } - method 'reduce (Ljava/util/function/IntBinaryOperator;)Ljava/util/OptionalInt;' { + method 'localMax (II)I' { 0 65 1 65 } - method 'function (Ljava/util/function/Supplier;)Ljava/lang/String;' { + method 'nestedLambdas ()V' { 0 69 1 69 - 2 69 - 3 69 - 4 69 - 5 69 - 6 69 - 7 69 - 8 69 - 9 69 - } - - method 'localMax (II)I' { - 0 73 - 1 73 - } - - method 'nestedLambdas ()V' { - 0 77 - 1 77 - 8 78 - 9 84 + 8 70 + 9 74 } method 'lambda$nestedLambdas$6 (I)V' { - 6 79 - 7 82 - 8 82 - 9 82 - 11 82 - 12 82 - 16 82 - 1a 82 - 1b 82 - 1c 82 - 1d 82 - 1e 82 - 1f 82 - 20 83 + 6 71 + 7 72 + 8 72 + 9 72 + 11 72 + 12 72 + 16 72 + 1a 72 + 1b 72 + 1c 72 + 1d 72 + 1e 72 + 1f 72 + 20 73 } method 'lambda$null$5 (I)V' { - 0 80 - 1 80 - 2 80 - a 80 - b 80 - f 80 - 13 80 - 14 80 - 15 80 - 16 80 - 17 80 - 18 80 - 19 81 + 0 71 + 1 71 + 2 71 + a 71 + b 71 + f 71 + 13 71 + 14 71 + 15 71 + 16 71 + 17 71 + 18 71 + 19 71 } } @@ -375,31 +365,31 @@ Lines mapping: 35 <-> 20 36 <-> 21 39 <-> 24 -40 <-> 26 -41 <-> 29 -42 <-> 31 -45 <-> 35 -46 <-> 37 -49 <-> 40 -50 <-> 41 -53 <-> 44 -54 <-> 45 -57 <-> 48 -58 <-> 49 -59 <-> 50 -62 <-> 53 -63 <-> 54 -64 <-> 55 -65 <-> 57 -66 <-> 59 -69 <-> 62 -70 <-> 63 -73 <-> 66 -77 <-> 70 -81 <-> 74 -85 <-> 78 -86 <-> 79 -87 <-> 81 -88 <-> 83 -89 <-> 84 -90 <-> 85 +40 <-> 25 +41 <-> 26 +42 <-> 27 +45 <-> 30 +46 <-> 31 +49 <-> 34 +50 <-> 35 +53 <-> 38 +54 <-> 39 +57 <-> 42 +58 <-> 43 +59 <-> 44 +62 <-> 47 +63 <-> 48 +64 <-> 49 +65 <-> 50 +66 <-> 51 +69 <-> 54 +70 <-> 55 +73 <-> 58 +77 <-> 62 +81 <-> 66 +85 <-> 70 +86 <-> 71 +87 <-> 72 +88 <-> 73 +89 <-> 74 +90 <-> 75 diff --git a/testData/results/pkg/TestDoubleNestedClass.dec b/testData/results/pkg/TestDoubleNestedClass.dec index 30ed96a38e..de767178f7 100644 --- a/testData/results/pkg/TestDoubleNestedClass.dec +++ b/testData/results/pkg/TestDoubleNestedClass.dec @@ -32,8 +32,7 @@ public abstract class TestDoubleNestedClass { Supplier foo(int var1) { byte var2 = 10; - return () -> { - return new TestDoubleNestedClass() { + return () -> new TestDoubleNestedClass() { @Override Object test() { int var1x = Child1.this.x + var1; @@ -41,7 +40,6 @@ public abstract class TestDoubleNestedClass { return Child1.this.x + var1x + var2x; } }; - }; } } } @@ -79,45 +77,45 @@ class 'pkg/TestDoubleNestedClass$Child1' { } method 'lambda$foo$0 (II)Lpkg/TestDoubleNestedClass;' { - a 35 + a 34 } } class 'pkg/TestDoubleNestedClass$Child1$1' { method 'test ()Ljava/lang/Object;' { - 1 38 - 2 38 - 3 38 - 4 38 - 5 38 - 6 38 - 8 38 - 9 38 - a 38 - b 38 - c 38 - e 39 - f 39 - 10 39 - 12 39 - 13 39 - 14 39 - 15 39 - 16 39 - 18 40 - 19 40 - 1a 40 - 1b 40 - 1c 40 - 1d 40 - 1e 40 - 1f 40 - 20 40 - 21 40 - 22 40 - 23 40 - 24 40 - 25 40 + 1 37 + 2 37 + 3 37 + 4 37 + 5 37 + 6 37 + 8 37 + 9 37 + a 37 + b 37 + c 37 + e 38 + f 38 + 10 38 + 12 38 + 13 38 + 14 38 + 15 38 + 16 38 + 18 39 + 19 39 + 1a 39 + 1b 39 + 1c 39 + 1d 39 + 1e 39 + 1f 39 + 20 39 + 21 39 + 22 39 + 23 39 + 24 39 + 25 39 } } diff --git a/testData/results/pkg/TestDuplicateLocals.dec b/testData/results/pkg/TestDuplicateLocals.dec index 55f15101c5..6516be840b 100644 --- a/testData/results/pkg/TestDuplicateLocals.dec +++ b/testData/results/pkg/TestDuplicateLocals.dec @@ -8,20 +8,14 @@ import java.util.function.Function; import java.util.function.Predicate; public class TestDuplicateLocals { - public static final Function> A = var0 -> { - return var0x -> { - return true; - }; - }; + public static final Function> A = var0 -> var0x -> true; private int i = 42; public void test1(List> var1) { System.out.println(var1); var1.forEach(var0 -> { System.out.println(var0); - var0.forEach(var1x -> { - System.out.println(var0); - }); + var0.forEach(var1x -> System.out.println(var0)); }); } @@ -29,9 +23,7 @@ public class TestDuplicateLocals { System.out.println(var0); var0.forEach(var0x -> { System.out.println(var0x); - var0x.forEach(var0xx -> { - System.out.println(var0xx); - }); + var0x.forEach(var0xx -> System.out.println(var0xx)); }); } @@ -40,9 +32,7 @@ public class TestDuplicateLocals { var1.forEach(var0 -> { int var1x = var0.size(); System.out.println(var0); - var0.forEach(var1xx -> { - System.out.println(var1x); - }); + var0.forEach(var1xx -> System.out.println(var1x)); }); } @@ -50,44 +40,30 @@ public class TestDuplicateLocals { System.out.println(var1); var1.forEach((var1x, var2) -> { System.out.println(var1x); - var1.forEach((var1xx, var2x) -> { - System.out.println(var1x); - }); + var1.forEach((var1xx, var2x) -> System.out.println(var1x)); }); } public static void test5(Optional var0) { - var0.ifPresent(var0x -> { - System.out.println(var0x); - }); + var0.ifPresent(var0x -> System.out.println(var0x)); } public void test6(Optional var1) { - var1.ifPresent(var1x -> { - System.out.println(this.i + " " + var1x); - }); + var1.ifPresent(var1x -> System.out.println(this.i + " " + var1x)); } public static Integer test7(int var0) { - return (Integer)(new HashMap()).computeIfAbsent(var0, var0x -> { - return var0x + 1; - }); + return (Integer)(new HashMap()).computeIfAbsent(var0, var0x -> var0x + 1); } public class Inner { public Integer test7(int var1) { - return (Integer)(new HashMap()).computeIfAbsent(var1, var1x -> { - return var1x + TestDuplicateLocals.this.i; - }); + return (Integer)(new HashMap()).computeIfAbsent(var1, var1x -> var1x + TestDuplicateLocals.this.i); } } interface Inner2 { - TestDuplicateLocals.Inner2 A = var0 -> { - return var0x -> { - return true; - }; - }; + TestDuplicateLocals.Inner2 A = var0 -> var0x -> true; Predicate getPredicate(Object var1); } @@ -95,49 +71,60 @@ public class TestDuplicateLocals { class 'pkg/TestDuplicateLocals' { method 'lambda$static$1 (Ljava/lang/Object;)Ljava/util/function/Predicate;' { - 5 11 + 5 10 } method 'lambda$null$0 (Ljava/lang/Object;)Z' { - 0 12 - 1 12 + 0 10 + 1 10 } method 'test1 (Ljava/util/List;)V' { - 0 18 - 1 18 - 2 18 - 3 18 - 4 18 - 5 18 - 6 18 - 7 19 - d 19 - e 19 - f 19 - 10 19 - 11 19 - 12 25 + 0 14 + 1 14 + 2 14 + 3 14 + 4 14 + 5 14 + 6 14 + 7 15 + d 15 + e 15 + f 15 + 10 15 + 11 15 + 12 19 } method 'lambda$test1$3 (Ljava/util/List;)V' { - 2 20 - 3 20 - 4 20 - 5 20 - 6 20 - 7 20 - 8 20 - 9 21 - 10 21 - 11 21 - 12 21 - 13 21 - 14 21 - 15 24 + 2 16 + 3 16 + 4 16 + 5 16 + 6 16 + 7 16 + 8 16 + 9 17 + 10 17 + 11 17 + 12 17 + 13 17 + 14 17 + 15 18 } method 'lambda$null$2 (Ljava/util/List;Ljava/lang/Object;)V' { + 0 17 + 1 17 + 2 17 + 3 17 + 4 17 + 5 17 + 6 17 + 7 17 + } + + method 'test2 (Ljava/util/List;)V' { 0 22 1 22 2 22 @@ -146,26 +133,43 @@ class 'pkg/TestDuplicateLocals' { 5 22 6 22 7 23 + d 23 + e 23 + f 23 + 10 23 + 11 23 + 12 27 } - method 'test2 (Ljava/util/List;)V' { - 0 28 - 1 28 - 2 28 - 3 28 - 4 28 - 5 28 - 6 28 - 7 29 - d 29 - e 29 - f 29 - 10 29 - 11 29 - 12 35 + method 'lambda$test2$5 (Ljava/util/List;)V' { + 0 24 + 1 24 + 2 24 + 3 24 + 4 24 + 5 24 + 6 24 + 7 25 + d 25 + e 25 + f 25 + 10 25 + 11 25 + 12 26 } - method 'lambda$test2$5 (Ljava/util/List;)V' { + method 'lambda$null$4 (Ljava/lang/Object;)V' { + 0 25 + 1 25 + 2 25 + 3 25 + 4 25 + 5 25 + 6 25 + 7 25 + } + + method 'test3 (Ljava/util/List;)V' { 0 30 1 30 2 30 @@ -179,10 +183,10 @@ class 'pkg/TestDuplicateLocals' { f 31 10 31 11 31 - 12 34 + 12 36 } - method 'lambda$null$4 (Ljava/lang/Object;)V' { + method 'lambda$test3$7 (Ljava/util/List;)V' { 0 32 1 32 2 32 @@ -191,222 +195,194 @@ class 'pkg/TestDuplicateLocals' { 5 32 6 32 7 33 - } - - method 'test3 (Ljava/util/List;)V' { - 0 38 - 1 38 - 2 38 - 3 38 - 4 38 - 5 38 - 6 38 - 7 39 - d 39 - e 39 - f 39 - 10 39 - 11 39 - 12 46 - } - - method 'lambda$test3$7 (Ljava/util/List;)V' { - 0 40 - 1 40 - 2 40 - 3 40 - 4 40 - 5 40 - 6 40 - 7 41 - 8 41 - 9 41 - a 41 - b 41 - c 41 - d 41 - e 42 - 15 42 - 16 42 - 17 42 - 18 42 - 19 42 - 1a 45 + 8 33 + 9 33 + a 33 + b 33 + c 33 + d 33 + e 34 + 15 34 + 16 34 + 17 34 + 18 34 + 19 34 + 1a 35 } method 'lambda$null$6 (ILjava/lang/Object;)V' { - 0 43 - 1 43 - 2 43 - 3 43 - 4 43 - 5 43 - 6 43 - 7 44 + 0 34 + 1 34 + 2 34 + 3 34 + 4 34 + 5 34 + 6 34 + 7 34 } method 'test4 (Ljava/util/Map;)V' { - 0 49 - 1 49 - 2 49 - 3 49 - 4 49 - 5 49 - 6 49 - 7 50 - e 50 - f 50 - 10 50 - 11 50 - 12 50 - 13 56 + 0 39 + 1 39 + 2 39 + 3 39 + 4 39 + 5 39 + 6 39 + 7 40 + e 40 + f 40 + 10 40 + 11 40 + 12 40 + 13 44 } method 'lambda$test4$9 (Ljava/util/Map;Ljava/lang/String;Ljava/util/List;)V' { - 0 51 - 1 51 - 2 51 - 3 51 - 4 51 - 5 51 - 6 51 - 7 52 - e 52 - f 52 - 10 52 - 11 52 - 12 52 - 13 55 + 0 41 + 1 41 + 2 41 + 3 41 + 4 41 + 5 41 + 6 41 + 7 42 + e 42 + f 42 + 10 42 + 11 42 + 12 42 + 13 43 } method 'lambda$null$8 (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V' { - 0 53 - 1 53 - 2 53 - 3 53 - 4 53 - 5 53 - 6 53 - 7 54 + 0 42 + 1 42 + 2 42 + 3 42 + 4 42 + 5 42 + 6 42 + 7 42 } method 'test5 (Ljava/util/Optional;)V' { - 0 59 - 6 59 - 7 59 - 8 59 - 9 62 + 0 47 + 6 47 + 7 47 + 8 47 + 9 48 } method 'lambda$test5$10 (Ljava/lang/Object;)V' { - 0 60 - 1 60 - 2 60 - 3 60 - 4 60 - 5 60 - 6 60 - 7 61 + 0 47 + 1 47 + 2 47 + 3 47 + 4 47 + 5 47 + 6 47 + 7 47 } method 'test6 (Ljava/util/Optional;)V' { - 0 65 - 7 65 - 8 65 - 9 65 - a 68 + 0 51 + 7 51 + 8 51 + 9 51 + a 52 } method 'lambda$test6$11 (Ljava/lang/Object;)V' { - 0 66 - 1 66 - 2 66 - a 66 - b 66 - c 66 - d 66 - 11 66 - 12 66 - 16 66 - 1a 66 - 1b 66 - 1c 66 - 1d 66 - 1e 66 - 1f 66 - 20 67 + 0 51 + 1 51 + 2 51 + a 51 + b 51 + c 51 + d 51 + 11 51 + 12 51 + 16 51 + 1a 51 + 1b 51 + 1c 51 + 1d 51 + 1e 51 + 1f 51 + 20 51 } method 'test7 (I)Ljava/lang/Integer;' { - 7 71 - 8 71 - 9 71 - a 71 - 10 71 - 11 71 - 12 71 - 13 71 - 14 71 - 15 71 - 16 71 + 7 55 + 8 55 + 9 55 + a 55 + 10 55 + 11 55 + 12 55 + 13 55 + 14 55 + 15 55 + 16 55 } method 'lambda$test7$12 (Ljava/lang/Integer;)Ljava/lang/Integer;' { - 0 72 - 1 72 - 2 72 - 3 72 - 4 72 - 5 72 - 6 72 - 7 72 - 8 72 - 9 72 + 0 55 + 1 55 + 2 55 + 3 55 + 4 55 + 5 55 + 6 55 + 7 55 + 8 55 + 9 55 } } class 'pkg/TestDuplicateLocals$Inner' { method 'test7 (I)Ljava/lang/Integer;' { - 7 78 - 8 78 - 9 78 - a 78 - 11 78 - 12 78 - 13 78 - 14 78 - 15 78 - 16 78 - 17 78 + 7 60 + 8 60 + 9 60 + a 60 + 11 60 + 12 60 + 13 60 + 14 60 + 15 60 + 16 60 + 17 60 } method 'lambda$test7$0 (Ljava/lang/Integer;)Ljava/lang/Integer;' { - 0 79 - 1 79 - 2 79 - 3 79 - 5 79 - 6 79 - 7 79 - 8 79 - 9 79 - a 79 - b 79 - c 79 - d 79 - e 79 - f 79 + 0 60 + 1 60 + 2 60 + 3 60 + 5 60 + 6 60 + 7 60 + 8 60 + 9 60 + a 60 + b 60 + c 60 + d 60 + e 60 + f 60 } } class 'pkg/TestDuplicateLocals$Inner2' { method 'lambda$static$1 (Ljava/lang/Object;)Ljava/util/function/Predicate;' { - 5 86 + 5 65 } method 'lambda$null$0 (Ljava/lang/Object;)Z' { - 0 87 - 1 87 + 0 65 + 1 65 } } diff --git a/testData/results/pkg/TestIfLoop.dec b/testData/results/pkg/TestIfLoop.dec index 986a91917a..f604e167a8 100644 --- a/testData/results/pkg/TestIfLoop.dec +++ b/testData/results/pkg/TestIfLoop.dec @@ -36,7 +36,10 @@ public class TestIfLoop { public void testCompound2(int a, int b, Random random) { a = random.nextInt(8) - random.nextInt(8) + a;// 41 - for(int var5 = random.nextInt(8) - random.nextInt(8) + b; a >= 0 && a <= 20 && var5 >= 0 && var5 <= 20; var5 -= random.nextInt(4) - random.nextInt(4)) {// 42 44 46 + for(int var5 = random.nextInt(8) - random.nextInt(8) + b;// 42 + a >= 0 && a <= 20 && var5 >= 0 && var5 <= 20;// 44 + var5 -= random.nextInt(4) - random.nextInt(4)// 46 + ) { a -= random.nextInt(4) - random.nextInt(4);// 45 } @@ -166,85 +169,85 @@ class 'pkg/TestIfLoop' { 1d 38 1e 38 1f 38 - 20 38 - 21 38 - 24 38 - 25 38 - 26 38 - 27 38 - 2a 38 - 2b 38 - 2e 38 - 2f 38 - 30 38 - 31 38 - 35 39 - 36 39 - 37 39 - 38 39 - 39 39 - 3a 39 - 3b 39 - 3c 39 - 3d 39 - 3e 39 - 3f 39 - 41 39 - 43 38 - 44 38 - 45 38 - 46 38 - 47 38 - 48 38 - 49 38 - 4a 38 - 4b 38 - 4c 38 - 4d 38 - 4f 38 - 53 42 + 20 39 + 21 39 + 24 39 + 25 39 + 26 39 + 27 39 + 2a 39 + 2b 39 + 2e 39 + 2f 39 + 30 39 + 31 39 + 35 42 + 36 42 + 37 42 + 38 42 + 39 42 + 3a 42 + 3b 42 + 3c 42 + 3d 42 + 3e 42 + 3f 42 + 41 42 + 43 40 + 44 40 + 45 40 + 46 40 + 47 40 + 48 40 + 49 40 + 4a 40 + 4b 40 + 4c 40 + 4d 40 + 4f 40 + 53 45 } method 'testElseIf (I)I' { - 0 45 - 1 45 - 4 46 - 5 46 - 6 46 - 7 46 - a 47 - b 47 - c 47 - 10 48 - 11 48 - 12 48 - 13 48 - 16 49 - 17 49 - 18 49 - 1c 50 - 1d 50 - 1e 50 - 1f 50 - 22 51 - 23 51 - 24 51 - 28 52 - 29 52 - 2a 52 - 2b 52 - 2f 53 - 31 53 - 35 55 - 36 55 - 37 55 - 38 55 - 3b 59 - 3c 59 - 3d 59 - 48 56 - 49 63 - 4a 63 + 0 48 + 1 48 + 4 49 + 5 49 + 6 49 + 7 49 + a 50 + b 50 + c 50 + 10 51 + 11 51 + 12 51 + 13 51 + 16 52 + 17 52 + 18 52 + 1c 53 + 1d 53 + 1e 53 + 1f 53 + 22 54 + 23 54 + 24 54 + 28 55 + 29 55 + 2a 55 + 2b 55 + 2f 56 + 31 56 + 35 58 + 36 58 + 37 58 + 38 58 + 3b 62 + 3c 62 + 3d 62 + 48 59 + 49 66 + 4a 66 } } @@ -266,20 +269,20 @@ Lines mapping: 37 <-> 33 41 <-> 37 42 <-> 39 -44 <-> 39 -45 <-> 40 -46 <-> 39 -48 <-> 43 -51 <-> 46 -52 <-> 47 -53 <-> 48 -54 <-> 49 -55 <-> 50 -56 <-> 51 -57 <-> 52 -58 <-> 53 -59 <-> 54 -60 <-> 56 -61 <-> 60 -63 <-> 57 -67 <-> 64 +44 <-> 40 +45 <-> 43 +46 <-> 41 +48 <-> 46 +51 <-> 49 +52 <-> 50 +53 <-> 51 +54 <-> 52 +55 <-> 53 +56 <-> 54 +57 <-> 55 +58 <-> 56 +59 <-> 57 +60 <-> 59 +61 <-> 63 +63 <-> 60 +67 <-> 67 diff --git a/testData/results/pkg/TestLambdaParams.dec b/testData/results/pkg/TestLambdaParams.dec index a68576588b..93dc55d29b 100644 --- a/testData/results/pkg/TestLambdaParams.dec +++ b/testData/results/pkg/TestLambdaParams.dec @@ -5,15 +5,9 @@ import java.util.function.Function; public class TestLambdaParams { public static void toCollection(Object collectionFactory) { Class a = null;// 23 - Function f = r1 -> { - return collectionFactory;// 24 - }; - Function f1 = r1 -> { - return a;// 25 - }; - Function f2 = r1 -> { - return r1;// 26 - }; + Function f = r1 -> collectionFactory;// 24 + Function f1 = r1 -> a;// 25 + Function f2 = r1 -> r1;// 26 }// 27 } @@ -22,31 +16,31 @@ class 'pkg/TestLambdaParams' { 0 6 1 6 8 7 - f 10 - 15 13 - 16 13 - 17 16 + f 8 + 15 9 + 16 9 + 17 10 } method 'lambda$toCollection$0 (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;' { - 0 8 - 1 8 + 0 7 + 1 7 } method 'lambda$toCollection$1 (Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/Object;' { - 0 11 - 1 11 + 0 8 + 1 8 } method 'lambda$toCollection$2 (Ljava/lang/Object;)Ljava/lang/Object;' { - 0 14 - 1 14 + 0 9 + 1 9 } } Lines mapping: 23 <-> 7 -24 <-> 9 -25 <-> 12 -26 <-> 15 -27 <-> 17 +24 <-> 8 +25 <-> 9 +26 <-> 10 +27 <-> 11 diff --git a/testData/results/pkg/TestLocalClass.dec b/testData/results/pkg/TestLocalClass.dec index 3993437475..87964d5fe9 100644 --- a/testData/results/pkg/TestLocalClass.dec +++ b/testData/results/pkg/TestLocalClass.dec @@ -29,9 +29,7 @@ public abstract class TestLocalClass { class C { } - Supplier constr = () -> { - return new C();// 30 - }; + Supplier constr = () -> new C();// 30 }// 31 } @@ -61,11 +59,11 @@ class 'pkg/TestLocalClass' { method 'bar ()V' { 6 31 - 7 34 + 7 32 } method 'lambda$bar$0 ()Lpkg/TestLocalClass$1C;' { - 8 32 + 8 31 } } @@ -91,5 +89,5 @@ Lines mapping: 22 <-> 22 25 <-> 25 26 <-> 26 -30 <-> 33 -31 <-> 35 +30 <-> 32 +31 <-> 33 diff --git a/testData/results/pkg/TestLocalRecord.dec b/testData/results/pkg/TestLocalRecord.dec index 5f4f1b46d4..fd05c44dfc 100644 --- a/testData/results/pkg/TestLocalRecord.dec +++ b/testData/results/pkg/TestLocalRecord.dec @@ -34,9 +34,7 @@ public class TestLocalRecord { record R() { } - Supplier constr = () -> { - return new R();// 29 - }; + Supplier constr = () -> new R();// 29 }// 30 } @@ -104,11 +102,11 @@ class 'pkg/TestLocalRecord' { method 'test4 ()V' { 5 36 - 6 39 + 6 37 } method 'lambda$test4$0 ()Lpkg/TestLocalRecord$3R;' { - 7 37 + 7 36 } } @@ -128,5 +126,5 @@ Lines mapping: 22 <-> 27 24 <-> 30 25 <-> 31 -29 <-> 38 -30 <-> 40 +29 <-> 37 +30 <-> 38 diff --git a/testData/results/pkg/TestLongMethodDeclaration.dec b/testData/results/pkg/TestLongMethodDeclaration.dec new file mode 100644 index 0000000000..4405974229 --- /dev/null +++ b/testData/results/pkg/TestLongMethodDeclaration.dec @@ -0,0 +1,32 @@ +package pkg; + +public class TestLongMethodDeclaration { + public void foo( + int param1, + int param2, + int param3, + int param4, + int param5, + int param6, + int param7, + int param8, + int param9, + int param10, + int param11, + int param12, + int param13, + int param14, + int param15, + int param16 + ) { + }// 21 +} + +class 'pkg/TestLongMethodDeclaration' { + method 'foo (IIIIIIIIIIIIIIII)V' { + 0 21 + } +} + +Lines mapping: +21 <-> 22 diff --git a/testData/results/pkg/TestLongMethodInvocation.dec b/testData/results/pkg/TestLongMethodInvocation.dec new file mode 100644 index 0000000000..ab2c0fe86c --- /dev/null +++ b/testData/results/pkg/TestLongMethodInvocation.dec @@ -0,0 +1,293 @@ +package pkg; + +public class TestLongMethodInvocation { + private TestLongMethodInvocation longField; + + public TestLongMethodInvocation longMethodInvocation() { + this.longMethodInvocation()// 7 + .longMethodInvocation()// 8 + .longMethodInvocation()// 9 + .longMethodInvocation()// 10 + .longMethodInvocation()// 11 + .longMethodInvocation()// 12 + .longMethodInvocation()// 13 + .longMethodInvocation()// 14 + .longMethodInvocation()// 15 + .longMethodInvocation()// 16 + .longMethodInvocation()// 17 + .longMethodInvocation()// 18 + .longMethodInvocation()// 19 + .longMethodInvocation()// 20 + .longMethodInvocation()// 21 + .longMethodInvocation();// 22 + return this;// 23 + } + + public void longFieldInvocation() { + this.longField// 27 + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longMethodInvocation();// 51 + }// 52 + + public void longMixture() { + this.longField// 55 + .longMethodInvocation()// 56 + .longField + .longMethodInvocation()// 58 + .longField + .longMethodInvocation()// 60 + .longField + .longMethodInvocation()// 62 + .longField + .longMethodInvocation()// 64 + .longField + .longMethodInvocation()// 66 + .longField + .longMethodInvocation()// 68 + .longField + .longMethodInvocation();// 70 + }// 71 +} + +class 'pkg/TestLongMethodInvocation' { + method 'longMethodInvocation ()Lpkg/TestLongMethodInvocation;' { + 0 6 + 1 6 + 2 6 + 3 6 + 4 7 + 5 7 + 6 7 + 7 8 + 8 8 + 9 8 + a 9 + b 9 + c 9 + d 10 + e 10 + f 10 + 10 11 + 11 11 + 12 11 + 13 12 + 14 12 + 15 12 + 16 13 + 17 13 + 18 13 + 19 14 + 1a 14 + 1b 14 + 1c 15 + 1d 15 + 1e 15 + 1f 16 + 20 16 + 21 16 + 22 17 + 23 17 + 24 17 + 25 18 + 26 18 + 27 18 + 28 19 + 29 19 + 2a 19 + 2b 20 + 2c 20 + 2d 20 + 2e 21 + 2f 21 + 30 21 + 32 22 + 33 22 + } + + method 'longFieldInvocation ()V' { + 0 26 + 1 26 + 2 26 + 3 26 + 4 27 + 5 27 + 6 27 + 7 28 + 8 28 + 9 28 + a 29 + b 29 + c 29 + d 30 + e 30 + f 30 + 10 31 + 11 31 + 12 31 + 13 32 + 14 32 + 15 32 + 16 33 + 17 33 + 18 33 + 19 34 + 1a 34 + 1b 34 + 1c 35 + 1d 35 + 1e 35 + 1f 36 + 20 36 + 21 36 + 22 37 + 23 37 + 24 37 + 25 38 + 26 38 + 27 38 + 28 39 + 29 39 + 2a 39 + 2b 40 + 2c 40 + 2d 40 + 2e 41 + 2f 41 + 30 41 + 31 42 + 32 42 + 33 42 + 34 43 + 35 43 + 36 43 + 37 44 + 38 44 + 39 44 + 3a 45 + 3b 45 + 3c 45 + 3d 46 + 3e 46 + 3f 46 + 40 47 + 41 47 + 42 47 + 43 48 + 44 48 + 45 48 + 46 49 + 47 49 + 48 49 + 49 50 + 4a 50 + 4b 50 + 4d 51 + } + + method 'longMixture ()V' { + 0 54 + 1 54 + 2 54 + 3 54 + 4 55 + 5 55 + 6 55 + 7 56 + 8 56 + 9 56 + a 57 + b 57 + c 57 + d 58 + e 58 + f 58 + 10 59 + 11 59 + 12 59 + 13 60 + 14 60 + 15 60 + 16 61 + 17 61 + 18 61 + 19 62 + 1a 62 + 1b 62 + 1c 63 + 1d 63 + 1e 63 + 1f 64 + 20 64 + 21 64 + 22 65 + 23 65 + 24 65 + 25 66 + 26 66 + 27 66 + 28 67 + 29 67 + 2a 67 + 2b 68 + 2c 68 + 2d 68 + 2e 69 + 2f 69 + 30 69 + 32 70 + } +} + +Lines mapping: +7 <-> 7 +8 <-> 8 +9 <-> 9 +10 <-> 10 +11 <-> 11 +12 <-> 12 +13 <-> 13 +14 <-> 14 +15 <-> 15 +16 <-> 16 +17 <-> 17 +18 <-> 18 +19 <-> 19 +20 <-> 20 +21 <-> 21 +22 <-> 22 +23 <-> 23 +27 <-> 27 +51 <-> 51 +52 <-> 52 +55 <-> 55 +56 <-> 56 +58 <-> 58 +60 <-> 60 +62 <-> 62 +64 <-> 64 +66 <-> 66 +68 <-> 68 +70 <-> 70 +71 <-> 71 diff --git a/testData/results/pkg/TestMethodHandles.dec b/testData/results/pkg/TestMethodHandles.dec index 9bdcce0d15..7f5a00ea52 100644 --- a/testData/results/pkg/TestMethodHandles.dec +++ b/testData/results/pkg/TestMethodHandles.dec @@ -36,7 +36,9 @@ public class TestMethodHandles { } public void test5() throws Throwable { - MethodHandle println = LOOKUP.findVirtual(PrintStream.class, "println", MethodType.methodType(Void.TYPE, Long.TYPE));// 36 + MethodHandle println = LOOKUP.findVirtual(// 36 + PrintStream.class, "println", MethodType.methodType(Void.TYPE, Long.TYPE) + ); int a = -5;// 37 println.invokeExact(System.out, (long)a);// 38 }// 39 @@ -197,36 +199,36 @@ class 'pkg/TestMethodHandles' { 0 38 1 38 2 38 - 3 38 - 4 38 - 5 38 - 6 38 - 7 38 - 8 38 - 9 38 - a 38 - b 38 - c 38 - d 38 - e 38 - f 38 + 3 39 + 4 39 + 5 39 + 6 39 + 7 39 + 8 39 + 9 39 + a 39 + b 39 + c 39 + d 39 + e 39 + f 39 10 38 11 38 12 38 13 38 - 14 39 - 15 39 - 16 39 - 17 40 - 18 40 - 19 40 - 1a 40 - 1b 40 - 1c 40 - 1d 40 - 1e 40 - 1f 40 - 20 41 + 14 41 + 15 41 + 16 41 + 17 42 + 18 42 + 19 42 + 1a 42 + 1b 42 + 1c 42 + 1d 42 + 1e 42 + 1f 42 + 20 43 } } @@ -248,6 +250,6 @@ Lines mapping: 31 <-> 34 32 <-> 35 36 <-> 39 -37 <-> 40 -38 <-> 41 -39 <-> 42 +37 <-> 42 +38 <-> 43 +39 <-> 44 diff --git a/testData/results/pkg/TestNestedLambdas.dec b/testData/results/pkg/TestNestedLambdas.dec index 257f8d8356..13db63c0e3 100644 --- a/testData/results/pkg/TestNestedLambdas.dec +++ b/testData/results/pkg/TestNestedLambdas.dec @@ -4,11 +4,7 @@ public class TestNestedLambdas { public void test() { int x = accept(i -> {// 6 if (i == 0) {// 7 - accept(j -> {// 8 - return j == 0 ? accept(k -> {// 9 - return i + j;// 10 - }) : i * j;// 12 - }); + accept(j -> j == 0 ? accept(k -> i + j) : i * j);// 8 9 10 12 } return i;// 17 @@ -32,14 +28,14 @@ class 'pkg/TestNestedLambdas' { 6 4 7 4 8 4 - 9 15 - a 15 - b 15 - c 15 - d 15 - e 15 - f 15 - 10 16 + 9 11 + a 11 + b 11 + c 11 + d 11 + e 11 + f 11 + 10 12 } method 'lambda$test$2 (I)I' { @@ -48,37 +44,37 @@ class 'pkg/TestNestedLambdas' { a 6 b 6 c 6 - e 13 - f 13 + e 9 + f 9 } method 'lambda$null$1 (II)I' { - 0 7 - 1 7 - b 7 - c 7 - d 7 - f 9 - 10 9 - 11 9 + 0 6 + 1 6 + b 6 + c 6 + d 6 + f 6 + 10 6 + 11 6 } method 'lambda$null$0 (III)I' { - 0 8 - 1 8 - 2 8 - 3 8 + 0 6 + 1 6 + 2 6 + 3 6 } method 'accept (Lpkg/TestNestedLambdas$Func;)I' { - 0 19 - 1 19 - 2 19 - 3 19 - 4 19 - 5 19 - 6 19 - 7 19 + 0 15 + 1 15 + 2 15 + 3 15 + 4 15 + 5 15 + 6 15 + 7 15 } } @@ -86,10 +82,10 @@ Lines mapping: 6 <-> 5 7 <-> 6 8 <-> 7 -9 <-> 8 -10 <-> 9 -12 <-> 10 -17 <-> 14 -20 <-> 16 -21 <-> 17 -24 <-> 20 +9 <-> 7 +10 <-> 7 +12 <-> 7 +17 <-> 10 +20 <-> 12 +21 <-> 13 +24 <-> 16 diff --git a/testData/results/pkg/TestPrimitives.dec b/testData/results/pkg/TestPrimitives.dec index d7cd098fbc..c76fd0779e 100644 --- a/testData/results/pkg/TestPrimitives.dec +++ b/testData/results/pkg/TestPrimitives.dec @@ -56,7 +56,16 @@ public class TestPrimitives { System.out.printf("%b, %d, %d, %d", this.getBoolean(), this.getByte(), this.getShort(), this.getInt());// 53 new TestPrimitives(false, (byte)123, (short)257, 40000, 123L, 3.14F, 1.618, 'A');// 55 new TestPrimitives('A', 1.618, 3.14F, 123L, 40000, (short)257, (byte)123, false);// 56 - new TestPrimitives(Boolean.valueOf("false"), Byte.valueOf("123"), Short.valueOf("257"), Integer.valueOf("40000"), Long.valueOf("123"), Float.valueOf("3.14"), Double.valueOf("1.618"), new Character('A'));// 57 58 + new TestPrimitives( + Boolean.valueOf("false"),// 57 + Byte.valueOf("123"), + Short.valueOf("257"), + Integer.valueOf("40000"), + Long.valueOf("123"), + Float.valueOf("3.14"),// 58 + Double.valueOf("1.618"), + new Character('A') + ); }// 59 private TestPrimitives(boolean bool, byte b, short s, int i, long l, float f, double d, char c) { @@ -645,534 +654,534 @@ class 'pkg/TestPrimitives' { 1b6 57 1b7 57 1b8 57 - 1c1 58 - 1c2 58 - 1c3 58 - 1c4 58 - 1c5 58 - 1c6 58 - 1c7 58 - 1c8 58 - 1c9 58 - 1ca 58 - 1cb 58 - 1cc 58 - 1cd 58 - 1ce 58 - 1cf 58 - 1d0 58 - 1d1 58 - 1d2 58 - 1d3 58 - 1d4 58 - 1d5 58 - 1d6 58 - 1d7 58 - 1d8 58 - 1d9 58 - 1da 58 - 1db 58 - 1dc 58 - 1dd 58 - 1de 58 - 1df 58 - 1e0 58 - 1e1 58 - 1e2 58 - 1e3 58 - 1e4 58 - 1e5 58 - 1e6 58 - 1e7 58 - 1e8 58 - 1e9 58 - 1ea 58 - 1eb 58 - 1ec 58 - 1ed 58 - 1ee 58 - 1ef 58 - 1f0 58 - 1f1 58 - 1f2 58 - 1f3 58 - 1f4 58 - 1f5 58 - 1f6 58 - 1f7 58 - 1f8 58 - 1fd 58 - 1fe 58 - 202 58 - 203 58 - 204 58 - 209 59 + 1c1 59 + 1c2 59 + 1c3 59 + 1c4 59 + 1c5 59 + 1c6 59 + 1c7 59 + 1c8 59 + 1c9 60 + 1ca 60 + 1cb 60 + 1cc 60 + 1cd 60 + 1ce 60 + 1cf 60 + 1d0 60 + 1d1 61 + 1d2 61 + 1d3 61 + 1d4 61 + 1d5 61 + 1d6 61 + 1d7 61 + 1d8 61 + 1d9 62 + 1da 62 + 1db 62 + 1dc 62 + 1dd 62 + 1de 62 + 1df 62 + 1e0 62 + 1e1 63 + 1e2 63 + 1e3 63 + 1e4 63 + 1e5 63 + 1e6 63 + 1e7 63 + 1e8 63 + 1e9 64 + 1ea 64 + 1eb 64 + 1ec 64 + 1ed 64 + 1ee 64 + 1ef 64 + 1f0 64 + 1f1 65 + 1f2 65 + 1f3 65 + 1f4 65 + 1f5 65 + 1f6 65 + 1f7 65 + 1f8 65 + 1fd 66 + 1fe 66 + 202 66 + 203 66 + 204 66 + 209 68 } method ' (ZBSIJFDC)V' { - 4 62 - 5 62 - 6 62 - 7 62 - 8 62 - 10 62 - 11 62 - 12 62 - 13 62 - 17 62 - 18 62 - 19 62 - 1a 62 - 1e 62 - 1f 62 - 20 62 - 21 62 - 25 62 - 26 62 - 27 62 - 28 62 - 29 62 - 2d 62 - 2e 62 - 2f 62 - 30 62 - 31 62 - 35 62 - 36 62 - 37 62 - 38 62 - 39 62 - 3e 62 - 3f 62 - 40 62 - 41 62 - 42 62 - 47 62 - 48 62 - 49 62 - 4a 62 - 4b 62 - 4d 62 - 4e 62 - 4f 62 - 51 63 + 4 71 + 5 71 + 6 71 + 7 71 + 8 71 + 10 71 + 11 71 + 12 71 + 13 71 + 17 71 + 18 71 + 19 71 + 1a 71 + 1e 71 + 1f 71 + 20 71 + 21 71 + 25 71 + 26 71 + 27 71 + 28 71 + 29 71 + 2d 71 + 2e 71 + 2f 71 + 30 71 + 31 71 + 35 71 + 36 71 + 37 71 + 38 71 + 39 71 + 3e 71 + 3f 71 + 40 71 + 41 71 + 42 71 + 47 71 + 48 71 + 49 71 + 4a 71 + 4b 71 + 4d 71 + 4e 71 + 4f 71 + 51 72 } method ' (Ljava/lang/Character;Ljava/lang/Double;Ljava/lang/Float;Ljava/lang/Long;Ljava/lang/Integer;Ljava/lang/Short;Ljava/lang/Byte;Ljava/lang/Boolean;)V' { - 4 66 - 5 66 - 6 66 - 7 66 - 8 66 - 10 66 - 11 66 - 15 66 - 16 66 - 1a 66 - 1b 66 - 1f 66 - 20 66 - 24 66 - 25 66 - 29 66 - 2e 66 - 33 66 - 35 66 - 36 66 - 37 66 - 39 67 + 4 75 + 5 75 + 6 75 + 7 75 + 8 75 + 10 75 + 11 75 + 15 75 + 16 75 + 1a 75 + 1b 75 + 1f 75 + 20 75 + 24 75 + 25 75 + 29 75 + 2e 75 + 33 75 + 35 75 + 36 75 + 37 75 + 39 76 } method 'printBoolean (Z)V' { - 0 70 - 1 70 - 2 70 - 3 70 - 4 70 - b 70 - c 70 - d 70 - e 70 - 10 70 - 11 70 - 12 70 - 14 71 + 0 79 + 1 79 + 2 79 + 3 79 + 4 79 + b 79 + c 79 + d 79 + e 79 + 10 79 + 11 79 + 12 79 + 14 80 } method 'printByte (B)V' { - 0 74 - 1 74 - 2 74 - 3 74 - 4 74 - b 74 - c 74 - d 74 - e 74 - 10 74 - 11 74 - 12 74 - 14 75 + 0 83 + 1 83 + 2 83 + 3 83 + 4 83 + b 83 + c 83 + d 83 + e 83 + 10 83 + 11 83 + 12 83 + 14 84 } method 'printShort (S)V' { - 0 78 - 1 78 - 2 78 - 3 78 - 4 78 - b 78 - c 78 - d 78 - e 78 - 10 78 - 11 78 - 12 78 - 14 79 + 0 87 + 1 87 + 2 87 + 3 87 + 4 87 + b 87 + c 87 + d 87 + e 87 + 10 87 + 11 87 + 12 87 + 14 88 } method 'printInt (I)V' { - 0 82 - 1 82 - 2 82 - 3 82 - 4 82 - b 82 - c 82 - d 82 - e 82 - 10 82 - 11 82 - 12 82 - 14 83 + 0 91 + 1 91 + 2 91 + 3 91 + 4 91 + b 91 + c 91 + d 91 + e 91 + 10 91 + 11 91 + 12 91 + 14 92 } method 'printLong (J)V' { - 0 86 - 1 86 - 2 86 - 3 86 - 4 86 - b 86 - c 86 - d 86 - e 86 - 10 86 - 11 86 - 12 86 - 14 87 + 0 95 + 1 95 + 2 95 + 3 95 + 4 95 + b 95 + c 95 + d 95 + e 95 + 10 95 + 11 95 + 12 95 + 14 96 } method 'printFloat (F)V' { - 0 90 - 1 90 - 2 90 - 3 90 - 4 90 - b 90 - c 90 - d 90 - e 90 - 10 90 - 11 90 - 12 90 - 14 91 + 0 99 + 1 99 + 2 99 + 3 99 + 4 99 + b 99 + c 99 + d 99 + e 99 + 10 99 + 11 99 + 12 99 + 14 100 } method 'printDouble (D)V' { - 0 94 - 1 94 - 2 94 - 3 94 - 4 94 - b 94 - c 94 - d 94 - e 94 - 10 94 - 11 94 - 12 94 - 14 95 + 0 103 + 1 103 + 2 103 + 3 103 + 4 103 + b 103 + c 103 + d 103 + e 103 + 10 103 + 11 103 + 12 103 + 14 104 } method 'printChar (C)V' { - 0 98 - 1 98 - 2 98 - 3 98 - 4 98 - b 98 - c 98 - d 98 - e 98 - 10 98 - 11 98 - 12 98 - 14 99 + 0 107 + 1 107 + 2 107 + 3 107 + 4 107 + b 107 + c 107 + d 107 + e 107 + 10 107 + 11 107 + 12 107 + 14 108 } method 'printBooleanBoxed (Ljava/lang/Boolean;)V' { - 0 102 - 1 102 - 2 102 - 3 102 - 4 102 - b 102 - d 102 - e 102 - f 102 - 11 103 + 0 111 + 1 111 + 2 111 + 3 111 + 4 111 + b 111 + d 111 + e 111 + f 111 + 11 112 } method 'printByteBoxed (Ljava/lang/Byte;)V' { - 0 106 - 1 106 - 2 106 - 3 106 - 4 106 - b 106 - d 106 - e 106 - f 106 - 11 107 + 0 115 + 1 115 + 2 115 + 3 115 + 4 115 + b 115 + d 115 + e 115 + f 115 + 11 116 } method 'printShortBoxed (Ljava/lang/Short;)V' { - 0 110 - 1 110 - 2 110 - 3 110 - 4 110 - b 110 - d 110 - e 110 - f 110 - 11 111 + 0 119 + 1 119 + 2 119 + 3 119 + 4 119 + b 119 + d 119 + e 119 + f 119 + 11 120 } method 'printIntBoxed (Ljava/lang/Integer;)V' { - 0 114 - 1 114 - 2 114 - 3 114 - 4 114 - b 114 - d 114 - e 114 - f 114 - 11 115 + 0 123 + 1 123 + 2 123 + 3 123 + 4 123 + b 123 + d 123 + e 123 + f 123 + 11 124 } method 'printLongBoxed (Ljava/lang/Long;)V' { - 0 118 - 1 118 - 2 118 - 3 118 - 4 118 - b 118 - d 118 - e 118 - f 118 - 11 119 + 0 127 + 1 127 + 2 127 + 3 127 + 4 127 + b 127 + d 127 + e 127 + f 127 + 11 128 } method 'printFloatBoxed (Ljava/lang/Float;)V' { - 0 122 - 1 122 - 2 122 - 3 122 - 4 122 - b 122 - d 122 - e 122 - f 122 - 11 123 + 0 131 + 1 131 + 2 131 + 3 131 + 4 131 + b 131 + d 131 + e 131 + f 131 + 11 132 } method 'printDoubleBoxed (Ljava/lang/Double;)V' { - 0 126 - 1 126 - 2 126 - 3 126 - 4 126 - b 126 - d 126 - e 126 - f 126 - 11 127 + 0 135 + 1 135 + 2 135 + 3 135 + 4 135 + b 135 + d 135 + e 135 + f 135 + 11 136 } method 'printCharBoxed (Ljava/lang/Character;)V' { - 0 130 - 1 130 - 2 130 - 3 130 - 4 130 - b 130 - d 130 - e 130 - f 130 - 11 131 + 0 139 + 1 139 + 2 139 + 3 139 + 4 139 + b 139 + d 139 + e 139 + f 139 + 11 140 } method 'getBoolean ()Z' { - 0 134 - 1 134 + 0 143 + 1 143 } method 'getByte ()B' { - 0 138 - 1 138 - 2 138 + 0 147 + 1 147 + 2 147 } method 'getShort ()S' { - 0 142 - 1 142 - 2 142 - 3 142 + 0 151 + 1 151 + 2 151 + 3 151 } method 'getInt ()I' { - 0 146 - 1 146 - 2 146 + 0 155 + 1 155 + 2 155 } method 'getInteger ()Ljava/lang/Integer;' { - 0 150 - 1 150 - 2 150 - 3 150 - 4 150 - 5 150 + 0 159 + 1 159 + 2 159 + 3 159 + 4 159 + 5 159 } method 'getCharacter ()Ljava/lang/Character;' { - 0 154 - 1 154 - 2 154 - 3 154 - 4 154 - 5 154 + 0 163 + 1 163 + 2 163 + 3 163 + 4 163 + 5 163 } method 'printNarrowed ()V' { - 0 158 - 1 158 - 2 158 - 3 158 - 4 158 - 5 158 - 6 158 - 7 158 - 8 158 - 9 159 - a 159 - b 159 - c 159 - d 159 - e 159 - f 159 - 10 159 - 11 159 - 12 160 + 0 167 + 1 167 + 2 167 + 3 167 + 4 167 + 5 167 + 6 167 + 7 167 + 8 167 + 9 168 + a 168 + b 168 + c 168 + d 168 + e 168 + f 168 + 10 168 + 11 168 + 12 169 } method 'constructor ()V' { - 4 163 - 9 164 + 4 172 + 9 173 } method 'compare (C)Z' { - 0 167 - 1 167 - 2 167 - a 167 - b 168 - c 168 - 14 168 - 15 169 - 16 169 - 17 169 - 1f 169 - 20 170 - 21 170 - 22 170 - 23 170 - 2b 170 - 2c 171 - 2d 171 - 2e 171 - 2f 171 - 37 171 - 38 172 - 39 172 - 3a 172 - 3b 172 - 43 172 - 44 173 - 45 173 - 46 173 - 47 173 - 4f 173 - 50 174 - 51 174 - 52 174 - 53 174 - 5b 174 - 5c 175 - 5d 175 - 5e 175 - 5f 175 - 67 175 - 68 176 - 69 176 - 6a 176 - 6b 176 - 73 176 - 74 177 - 75 177 - 76 177 - 77 177 - 7f 177 - 80 178 - 81 178 - 82 178 - 83 178 - 8b 178 - 8c 179 - 8d 179 - 8e 179 - 8f 179 - 90 179 - 9a 179 + 0 176 + 1 176 + 2 176 + a 176 + b 177 + c 177 + 14 177 + 15 178 + 16 178 + 17 178 + 1f 178 + 20 179 + 21 179 + 22 179 + 23 179 + 2b 179 + 2c 180 + 2d 180 + 2e 180 + 2f 180 + 37 180 + 38 181 + 39 181 + 3a 181 + 3b 181 + 43 181 + 44 182 + 45 182 + 46 182 + 47 182 + 4f 182 + 50 183 + 51 183 + 52 183 + 53 183 + 5b 183 + 5c 184 + 5d 184 + 5e 184 + 5f 184 + 67 184 + 68 185 + 69 185 + 6a 185 + 6b 185 + 73 185 + 74 186 + 75 186 + 76 186 + 77 186 + 7f 186 + 80 187 + 81 187 + 82 187 + 83 187 + 8b 187 + 8c 188 + 8d 188 + 8e 188 + 8f 188 + 90 188 + 9a 188 } method 'testAutoBoxingCallRequired (Z)V' { - 0 183 - 1 183 - 2 183 - 3 183 - 4 183 - 5 183 - 6 183 - 8 184 + 0 192 + 1 192 + 2 192 + 3 192 + 4 192 + 5 192 + 6 192 + 8 193 } method 'testCastRequired ()V' { - 7 187 - 8 188 - 9 188 - a 188 - b 188 - c 188 - d 188 - e 188 - f 188 - 10 188 - 11 188 - 13 189 + 7 196 + 8 197 + 9 197 + a 197 + b 197 + c 197 + d 197 + e 197 + f 197 + 10 197 + 11 197 + 13 198 } } @@ -1219,75 +1228,75 @@ Lines mapping: 53 <-> 56 55 <-> 57 56 <-> 58 -57 <-> 59 -58 <-> 59 -59 <-> 60 -62 <-> 63 -63 <-> 64 -66 <-> 67 -67 <-> 68 -70 <-> 71 -71 <-> 72 -74 <-> 75 -75 <-> 76 -78 <-> 79 -79 <-> 80 -82 <-> 83 -83 <-> 84 -86 <-> 87 -87 <-> 88 -90 <-> 91 -91 <-> 92 -94 <-> 95 -95 <-> 96 -98 <-> 99 -99 <-> 100 -103 <-> 103 -104 <-> 104 -107 <-> 107 -108 <-> 108 -111 <-> 111 -112 <-> 112 -115 <-> 115 -116 <-> 116 -119 <-> 119 -120 <-> 120 -123 <-> 123 -124 <-> 124 -127 <-> 127 -128 <-> 128 -131 <-> 131 -132 <-> 132 -136 <-> 135 -140 <-> 139 -144 <-> 143 -148 <-> 147 -152 <-> 151 -156 <-> 155 -160 <-> 159 -161 <-> 160 -162 <-> 161 -165 <-> 164 -166 <-> 165 -169 <-> 168 -170 <-> 169 -171 <-> 170 -172 <-> 171 -173 <-> 172 -174 <-> 173 -175 <-> 174 -176 <-> 175 -177 <-> 176 -178 <-> 177 -179 <-> 178 -180 <-> 179 -181 <-> 180 -182 <-> 180 -186 <-> 184 -187 <-> 185 -190 <-> 188 -191 <-> 189 -192 <-> 190 +57 <-> 60 +58 <-> 65 +59 <-> 69 +62 <-> 72 +63 <-> 73 +66 <-> 76 +67 <-> 77 +70 <-> 80 +71 <-> 81 +74 <-> 84 +75 <-> 85 +78 <-> 88 +79 <-> 89 +82 <-> 92 +83 <-> 93 +86 <-> 96 +87 <-> 97 +90 <-> 100 +91 <-> 101 +94 <-> 104 +95 <-> 105 +98 <-> 108 +99 <-> 109 +103 <-> 112 +104 <-> 113 +107 <-> 116 +108 <-> 117 +111 <-> 120 +112 <-> 121 +115 <-> 124 +116 <-> 125 +119 <-> 128 +120 <-> 129 +123 <-> 132 +124 <-> 133 +127 <-> 136 +128 <-> 137 +131 <-> 140 +132 <-> 141 +136 <-> 144 +140 <-> 148 +144 <-> 152 +148 <-> 156 +152 <-> 160 +156 <-> 164 +160 <-> 168 +161 <-> 169 +162 <-> 170 +165 <-> 173 +166 <-> 174 +169 <-> 177 +170 <-> 178 +171 <-> 179 +172 <-> 180 +173 <-> 181 +174 <-> 182 +175 <-> 183 +176 <-> 184 +177 <-> 185 +178 <-> 186 +179 <-> 187 +180 <-> 188 +181 <-> 189 +182 <-> 189 +186 <-> 193 +187 <-> 194 +190 <-> 197 +191 <-> 198 +192 <-> 199 Not mapped: 61 65 diff --git a/testData/results/pkg/TestRecordBig.dec b/testData/results/pkg/TestRecordBig.dec new file mode 100644 index 0000000000..fb93212751 --- /dev/null +++ b/testData/results/pkg/TestRecordBig.dec @@ -0,0 +1,21 @@ +package pkg; + +public record TestRecordBig( + int comp1, + int comp2, + int comp3, + int comp4, + int comp5, + int comp6, + int comp7, + int comp8, + int comp9, + int comp10, + int comp11, + int comp12, + int comp13, + int comp14, + int comp15, + int comp16) { +} + diff --git a/testData/results/pkg/TestStaticInit.dec b/testData/results/pkg/TestStaticInit.dec index 0c2c26be2b..b8d39e0c66 100644 --- a/testData/results/pkg/TestStaticInit.dec +++ b/testData/results/pkg/TestStaticInit.dec @@ -3,9 +3,7 @@ package pkg; import java.util.function.Supplier; public class TestStaticInit { - static final Supplier X = () -> { - return TestStaticInit.Inner.Y;// 7 - }; + static final Supplier X = () -> TestStaticInit.Inner.Y;// 7 static final TestStaticInit Y = null; static class Inner { @@ -15,12 +13,12 @@ public class TestStaticInit { class 'pkg/TestStaticInit' { method 'lambda$static$0 ()Lpkg/TestStaticInit;' { - 0 6 - 1 6 - 2 6 - 3 6 + 0 5 + 1 5 + 2 5 + 3 5 } } Lines mapping: -7 <-> 7 +7 <-> 6 diff --git a/testData/results/pkg/TestSuspendLambdaKt.dec b/testData/results/pkg/TestSuspendLambdaKt.dec index 21e2a18119..aca16adb51 100644 --- a/testData/results/pkg/TestSuspendLambdaKt.dec +++ b/testData/results/pkg/TestSuspendLambdaKt.dec @@ -20,7 +20,9 @@ import org.jetbrains.annotations.Nullable; ) public final class TestSuspendLambdaKt { @NotNull - private static final Function1, Object> sl1 = new NamelessClass_1((Continuation)null); + private static final Function1, Object> sl1 = new NamelessClass_1( + (Continuation)null + ); @NotNull public static final Function1, Object> getSl1() { @@ -82,91 +84,91 @@ public final class TestSuspendLambdaKt { class 'pkg/TestSuspendLambdaKt' { method 'getSl1 ()Lkotlin/jvm/functions/Function1;' { - 0 26 - 1 26 - 2 26 - 3 26 + 0 28 + 1 28 + 2 28 + 3 28 } method ' ()V' { - e 79 + e 81 } } class 'pkg/TestSuspendLambdaKt$sl1$1' { method ' (Lkotlin/coroutines/Continuation;)V' { - 1 50 - 2 50 - 3 50 - 4 50 - 5 50 - 6 51 + 1 52 + 2 52 + 3 52 + 4 52 + 5 52 + 6 53 } method 'invokeSuspend (Ljava/lang/Object;)Ljava/lang/Object;' { - 0 55 - 1 55 - 2 55 - 3 55 - 4 55 - 5 56 - 6 56 - 7 56 - 8 56 - 9 56 - 1c 58 - 1d 58 - 1e 58 - 1f 58 - 20 59 - 21 59 - 22 59 - 23 60 - 24 60 - 25 61 - 26 61 - 27 61 - 28 61 - 29 61 - 2a 61 - 2b 61 - 2c 62 - 2d 62 - 2e 62 - 2f 62 - 34 64 - 35 64 - 39 64 + 0 57 + 1 57 + 2 57 + 3 57 + 4 57 + 5 58 + 6 58 + 7 58 + 8 58 + 9 58 + 1c 60 + 1d 60 + 1e 60 + 1f 60 + 20 61 + 21 61 + 22 61 + 23 62 + 24 62 + 25 63 + 26 63 + 27 63 + 28 63 + 29 63 + 2a 63 + 2b 63 + 2c 64 + 2d 64 + 2e 64 + 2f 64 + 34 66 + 35 66 + 39 66 } method 'create (Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;' { - 4 70 - 8 70 - 9 70 - a 70 - b 70 + 4 72 + 8 72 + 9 72 + a 72 + b 72 } method 'invoke (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;' { - 0 75 - 1 75 - 2 75 - 3 75 - 4 75 - 5 75 - 6 75 - 7 75 - 8 75 - 9 75 - a 75 - b 75 - c 75 - d 75 - e 75 + 0 77 + 1 77 + 2 77 + 3 77 + 4 77 + 5 77 + 6 77 + 7 77 + 8 77 + 9 77 + a 77 + b 77 + c 77 + d 77 + e 77 } } Lines mapping: -3 <-> 80 -4 <-> 60 -5 <-> 63 +3 <-> 82 +4 <-> 62 +5 <-> 65 diff --git a/testData/results/pkg/TestSwitchPatternMatching2.dec b/testData/results/pkg/TestSwitchPatternMatching2.dec index cfee549822..e540ec9d80 100644 --- a/testData/results/pkg/TestSwitchPatternMatching2.dec +++ b/testData/results/pkg/TestSwitchPatternMatching2.dec @@ -8,7 +8,9 @@ public class TestSwitchPatternMatching2 { byte var2 = 0; while(true) { - switch(SwitchBootstraps.typeSwitch<"typeSwitch",TestSwitchPatternMatching2.Triangle,TestSwitchPatternMatching2.Triangle>(var1, var2)) { + switch(SwitchBootstraps.typeSwitch<"typeSwitch",TestSwitchPatternMatching2.Triangle,TestSwitchPatternMatching2.Triangle>( + var1, var2 + )) { case -1: System.out.println("null");// 11 return;// 15 @@ -50,87 +52,87 @@ class 'pkg/TestSwitchPatternMatching2' { 1 6 2 7 3 7 - 4 10 - 5 10 + 4 11 + 5 11 6 10 7 10 8 10 9 10 a 10 b 10 - 24 15 - 25 15 - 26 15 - 27 15 - 28 15 - 29 16 - 2a 16 - 2b 16 - 2c 16 - 2d 16 - 2e 16 - 2f 16 - 30 16 - 31 16 - 34 17 - 35 17 - 36 18 - 39 21 - 3a 21 - 3b 21 - 3c 21 - 3d 21 - 3e 21 - 3f 21 - 40 21 - 44 24 - 45 24 - 46 24 - 47 24 - 48 24 - 49 24 - 4a 25 - 4b 25 - 4c 25 - 4d 25 - 4e 25 - 4f 25 - 50 25 - 51 25 - 55 12 - 56 12 - 57 12 - 58 12 - 59 12 - 5a 12 - 5b 12 - 5c 12 - 60 28 - 61 28 - 62 28 - 63 28 - 64 28 - 65 28 - 66 28 - 67 28 - 6b 13 + 24 17 + 25 17 + 26 17 + 27 17 + 28 17 + 29 18 + 2a 18 + 2b 18 + 2c 18 + 2d 18 + 2e 18 + 2f 18 + 30 18 + 31 18 + 34 19 + 35 19 + 36 20 + 39 23 + 3a 23 + 3b 23 + 3c 23 + 3d 23 + 3e 23 + 3f 23 + 40 23 + 44 26 + 45 26 + 46 26 + 47 26 + 48 26 + 49 26 + 4a 27 + 4b 27 + 4c 27 + 4d 27 + 4e 27 + 4f 27 + 50 27 + 51 27 + 55 14 + 56 14 + 57 14 + 58 14 + 59 14 + 5a 14 + 5b 14 + 5c 14 + 60 30 + 61 30 + 62 30 + 63 30 + 64 30 + 65 30 + 66 30 + 67 30 + 6b 15 } } class 'pkg/TestSwitchPatternMatching2$Triangle' { method 'calculateArea ()D' { - 0 41 - 1 41 + 0 43 + 1 43 } } Lines mapping: 5 <-> 7 -6 <-> 16 -7 <-> 22 -8 <-> 25 -9 <-> 26 -11 <-> 13 -13 <-> 29 -15 <-> 14 -25 <-> 42 +6 <-> 18 +7 <-> 24 +8 <-> 27 +9 <-> 28 +11 <-> 15 +13 <-> 31 +15 <-> 16 +25 <-> 44 diff --git a/testData/results/pkg/TestSwitchPatternMatching5.dec b/testData/results/pkg/TestSwitchPatternMatching5.dec index 35f362ac90..84a6333075 100644 --- a/testData/results/pkg/TestSwitchPatternMatching5.dec +++ b/testData/results/pkg/TestSwitchPatternMatching5.dec @@ -8,7 +8,9 @@ public class TestSwitchPatternMatching5 { byte var2 = 0; while(true) { - switch(SwitchBootstraps.typeSwitch<"typeSwitch",TestSwitchPatternMatching5.Triangle,TestSwitchPatternMatching5.Triangle,TestSwitchPatternMatching5.Triangle,TestSwitchPatternMatching5.Triangle>(var1, var2)) { + switch(SwitchBootstraps.typeSwitch<"typeSwitch",TestSwitchPatternMatching5.Triangle,TestSwitchPatternMatching5.Triangle,TestSwitchPatternMatching5.Triangle,TestSwitchPatternMatching5.Triangle>( + var1, var2 + )) { case -1: System.out.println("null");// 15 return;// 19 @@ -68,145 +70,145 @@ class 'pkg/TestSwitchPatternMatching5' { 1 6 2 7 3 7 - 4 10 - 5 10 + 4 11 + 5 11 6 10 7 10 8 10 9 10 a 10 b 10 - 2c 15 - 2d 15 - 2e 15 - 2f 15 - 30 15 - 31 16 - 32 16 - 33 16 - 34 16 - 35 16 - 36 16 - 37 16 - 38 16 - 39 16 - 3c 17 - 3d 17 - 3e 18 - 41 21 - 42 21 - 43 21 - 44 21 - 45 21 - 46 21 - 47 21 - 48 21 - 4c 24 - 4d 24 - 4e 24 - 4f 24 - 50 24 - 51 24 - 52 25 - 53 25 - 54 25 - 55 25 - 56 25 - 57 25 - 58 25 - 59 25 - 5a 25 - 5b 25 - 5e 26 - 5f 26 - 60 27 - 63 30 - 64 30 - 65 30 - 66 30 - 67 30 - 68 30 - 69 30 - 6a 30 - 6e 33 - 6f 33 - 70 33 - 71 33 - 72 33 - 73 33 - 74 34 - 75 34 - 76 34 - 77 34 - 78 34 - 79 34 - 7a 34 - 7b 34 - 7c 34 - 7d 34 - 80 35 - 81 35 - 82 36 - 85 39 - 86 39 - 87 39 - 88 39 - 89 39 - 8a 39 - 8b 39 - 8c 39 - 90 42 - 91 42 - 92 42 - 93 42 - 94 42 - 95 42 - 96 43 - 97 43 - 98 43 - 99 43 - 9a 43 - 9b 43 - 9c 43 - 9d 43 - a1 12 - a2 12 - a3 12 - a4 12 - a5 12 - a6 12 - a7 12 - a8 12 - ac 46 - ad 46 - ae 46 - af 46 - b0 46 - b1 46 - b2 46 - b3 46 - b7 13 + 2c 17 + 2d 17 + 2e 17 + 2f 17 + 30 17 + 31 18 + 32 18 + 33 18 + 34 18 + 35 18 + 36 18 + 37 18 + 38 18 + 39 18 + 3c 19 + 3d 19 + 3e 20 + 41 23 + 42 23 + 43 23 + 44 23 + 45 23 + 46 23 + 47 23 + 48 23 + 4c 26 + 4d 26 + 4e 26 + 4f 26 + 50 26 + 51 26 + 52 27 + 53 27 + 54 27 + 55 27 + 56 27 + 57 27 + 58 27 + 59 27 + 5a 27 + 5b 27 + 5e 28 + 5f 28 + 60 29 + 63 32 + 64 32 + 65 32 + 66 32 + 67 32 + 68 32 + 69 32 + 6a 32 + 6e 35 + 6f 35 + 70 35 + 71 35 + 72 35 + 73 35 + 74 36 + 75 36 + 76 36 + 77 36 + 78 36 + 79 36 + 7a 36 + 7b 36 + 7c 36 + 7d 36 + 80 37 + 81 37 + 82 38 + 85 41 + 86 41 + 87 41 + 88 41 + 89 41 + 8a 41 + 8b 41 + 8c 41 + 90 44 + 91 44 + 92 44 + 93 44 + 94 44 + 95 44 + 96 45 + 97 45 + 98 45 + 99 45 + 9a 45 + 9b 45 + 9c 45 + 9d 45 + a1 14 + a2 14 + a3 14 + a4 14 + a5 14 + a6 14 + a7 14 + a8 14 + ac 48 + ad 48 + ae 48 + af 48 + b0 48 + b1 48 + b2 48 + b3 48 + b7 15 } } class 'pkg/TestSwitchPatternMatching5$Triangle' { method 'calculateArea ()D' { - 0 59 - 1 59 + 0 61 + 1 61 } } Lines mapping: 5 <-> 7 -6 <-> 16 -7 <-> 22 -8 <-> 25 -9 <-> 31 -10 <-> 34 -11 <-> 40 -12 <-> 43 -13 <-> 44 -15 <-> 13 -17 <-> 47 -19 <-> 14 -29 <-> 60 +6 <-> 18 +7 <-> 24 +8 <-> 27 +9 <-> 33 +10 <-> 36 +11 <-> 42 +12 <-> 45 +13 <-> 46 +15 <-> 15 +17 <-> 49 +19 <-> 16 +29 <-> 62 diff --git a/testData/results/pkg/TestSwitchPatternMatchingConstructor1.dec b/testData/results/pkg/TestSwitchPatternMatchingConstructor1.dec index 3ac5c9ecea..cc9c13d05a 100644 --- a/testData/results/pkg/TestSwitchPatternMatchingConstructor1.dec +++ b/testData/results/pkg/TestSwitchPatternMatchingConstructor1.dec @@ -14,7 +14,9 @@ public class TestSwitchPatternMatchingConstructor1 { String var10001; label17: while(true) { - switch(SwitchBootstraps.typeSwitch<"typeSwitch",TestSwitchPatternMatchingConstructor1.Triangle,TestSwitchPatternMatchingConstructor1.Triangle>(var2, var3)) { + switch(SwitchBootstraps.typeSwitch<"typeSwitch",TestSwitchPatternMatchingConstructor1.Triangle,TestSwitchPatternMatchingConstructor1.Triangle>( + var2, var3 + )) { case -1: var10001 = "null";// 12 break label17; @@ -69,74 +71,74 @@ class 'pkg/TestSwitchPatternMatchingConstructor1' { 2 10 3 11 4 11 - 5 16 - 6 16 + 5 17 + 6 17 7 16 8 16 9 16 a 16 b 16 c 16 - 28 21 - 29 21 - 2a 21 - 2b 21 - 2c 21 - 2d 21 - 2e 22 - 2f 22 - 30 22 - 31 22 - 32 22 - 33 22 - 34 22 - 35 22 - 36 22 - 37 22 - 3a 23 - 3b 23 - 3c 24 - 3f 27 - 40 27 - 41 28 - 44 30 - 45 30 - 46 30 - 47 30 - 48 30 - 49 30 - 4a 31 - 4b 31 - 4c 32 - 4f 18 - 50 18 - 51 19 - 54 34 - 55 34 - 56 35 - 59 39 - 5a 39 - 5b 39 - 5c 40 + 28 23 + 29 23 + 2a 23 + 2b 23 + 2c 23 + 2d 23 + 2e 24 + 2f 24 + 30 24 + 31 24 + 32 24 + 33 24 + 34 24 + 35 24 + 36 24 + 37 24 + 3a 25 + 3b 25 + 3c 26 + 3f 29 + 40 29 + 41 30 + 44 32 + 45 32 + 46 32 + 47 32 + 48 32 + 49 32 + 4a 33 + 4b 33 + 4c 34 + 4f 20 + 50 20 + 51 21 + 54 36 + 55 36 + 56 37 + 59 41 + 5a 41 + 5b 41 + 5c 42 } } class 'pkg/TestSwitchPatternMatchingConstructor1$Triangle' { method 'calculateArea ()D' { - 0 49 - 1 49 + 0 51 + 1 51 } } Lines mapping: 5 <-> 7 6 <-> 8 -9 <-> 40 -10 <-> 22 -11 <-> 31 -12 <-> 19 -13 <-> 35 -15 <-> 41 -25 <-> 50 +9 <-> 42 +10 <-> 24 +11 <-> 33 +12 <-> 21 +13 <-> 37 +15 <-> 43 +25 <-> 52 Not mapped: 4 diff --git a/testData/results/pkg/TestUnionType.dec b/testData/results/pkg/TestUnionType.dec index 8e68537a3a..faa2aac295 100644 --- a/testData/results/pkg/TestUnionType.dec +++ b/testData/results/pkg/TestUnionType.dec @@ -4,9 +4,7 @@ import java.util.Comparator; public interface TestUnionType { static Comparator comparingInt() { - return (c1, c2) -> { - return 1;// 8 - }; + return (c1, c2) -> 1;// 8 } } @@ -22,10 +20,10 @@ class 'pkg/TestUnionType' { } method 'lambda$comparingInt$ff46620a$1 (Ljava/lang/Object;Ljava/lang/Object;)I' { - 0 7 - 1 7 + 0 6 + 1 6 } } Lines mapping: -8 <-> 8 +8 <-> 7 diff --git a/testData/results/pkg/TestWhileTernary10.dec b/testData/results/pkg/TestWhileTernary10.dec index 26b7bac076..42023ebef1 100644 --- a/testData/results/pkg/TestWhileTernary10.dec +++ b/testData/results/pkg/TestWhileTernary10.dec @@ -15,9 +15,7 @@ public class TestWhileTernary10 { } } - doubles.forEach(d -> { - ds[0] -= d;// 19 - }); + doubles.forEach(d -> ds[0] -= d);// 19 return ds[0];// 20 } @@ -28,9 +26,7 @@ public class TestWhileTernary10 { ds[0] += (double)i;// 27 } - doubles.forEach(d -> { - ds[0] -= d;// 30 - }); + doubles.forEach(d -> ds[0] -= d);// 30 return ds[0];// 31 } @@ -48,9 +44,7 @@ public class TestWhileTernary10 { } } - doubles.forEach(d -> { - ds[0] -= d;// 49 - }); + doubles.forEach(d -> ds[0] -= d);// 49 return ds[0];// 50 } } @@ -105,151 +99,151 @@ class 'pkg/TestWhileTernary10' { 50 17 51 17 52 17 - 53 20 - 54 20 - 55 20 - 56 20 - 57 20 + 53 18 + 54 18 + 55 18 + 56 18 + 57 18 } method 'lambda$test$0 ([DLjava/lang/Double;)V' { - 0 18 - 1 18 - 4 18 - 5 18 - 6 18 - 7 18 - 9 18 - a 19 + 0 17 + 1 17 + 4 17 + 5 17 + 6 17 + 7 17 + 9 17 + a 17 } method 'test1 (ZILjava/util/stream/Stream;)D' { - 5 24 - 6 24 - 8 24 - 9 24 - a 26 - b 26 - c 26 - d 26 - 11 26 - 12 26 - 13 26 - 14 26 - 1a 26 - 1b 26 - 1c 26 - 1d 26 - 20 27 - 21 27 - 22 27 - 25 27 - 26 27 - 27 27 - 29 27 - 2a 26 - 2b 26 - 2c 26 - 30 30 - 38 30 - 39 30 - 3a 30 - 3b 30 - 3c 30 - 3d 33 - 3e 33 - 3f 33 - 40 33 - 41 33 + 5 22 + 6 22 + 8 22 + 9 22 + a 24 + b 24 + c 24 + d 24 + 11 24 + 12 24 + 13 24 + 14 24 + 1a 24 + 1b 24 + 1c 24 + 1d 24 + 20 25 + 21 25 + 22 25 + 25 25 + 26 25 + 27 25 + 29 25 + 2a 24 + 2b 24 + 2c 24 + 30 28 + 38 28 + 39 28 + 3a 28 + 3b 28 + 3c 28 + 3d 29 + 3e 29 + 3f 29 + 40 29 + 41 29 } method 'lambda$test1$1 ([DLjava/lang/Double;)V' { - 0 31 - 1 31 - 4 31 - 5 31 - 6 31 - 7 31 - 9 31 - a 32 + 0 28 + 1 28 + 4 28 + 5 28 + 6 28 + 7 28 + 9 28 + a 28 } method 'test2 (ZILjava/util/stream/Stream;)D' { - 5 37 - 6 37 - 8 37 - 9 37 - a 39 - b 39 - c 39 - d 39 - 11 39 - 12 39 - 13 39 - 14 39 - 1a 39 - 1b 39 - 1c 39 - 1d 39 - 20 40 - 21 40 - 22 40 - 23 40 - 24 40 - 25 40 - 26 40 - 29 41 - 2a 41 - 2b 41 - 2c 41 - 2d 41 - 2e 41 - 2f 41 - 30 41 - 33 42 - 34 42 - 35 42 - 36 42 - 37 42 - 38 42 - 39 42 - 3a 43 - 3b 43 - 3c 43 - 3d 43 - 3e 43 - 41 44 - 44 41 - 45 41 - 46 41 - 4a 40 - 4b 40 - 4c 40 - 50 39 - 51 39 - 52 39 - 56 50 - 5e 50 - 5f 50 - 60 50 - 61 50 - 62 50 - 63 53 - 64 53 - 65 53 - 66 53 - 67 53 + 5 33 + 6 33 + 8 33 + 9 33 + a 35 + b 35 + c 35 + d 35 + 11 35 + 12 35 + 13 35 + 14 35 + 1a 35 + 1b 35 + 1c 35 + 1d 35 + 20 36 + 21 36 + 22 36 + 23 36 + 24 36 + 25 36 + 26 36 + 29 37 + 2a 37 + 2b 37 + 2c 37 + 2d 37 + 2e 37 + 2f 37 + 30 37 + 33 38 + 34 38 + 35 38 + 36 38 + 37 38 + 38 38 + 39 38 + 3a 39 + 3b 39 + 3c 39 + 3d 39 + 3e 39 + 41 40 + 44 37 + 45 37 + 46 37 + 4a 36 + 4b 36 + 4c 36 + 50 35 + 51 35 + 52 35 + 56 46 + 5e 46 + 5f 46 + 60 46 + 61 46 + 62 46 + 63 47 + 64 47 + 65 47 + 66 47 + 67 47 } method 'lambda$test2$2 ([DLjava/lang/Double;)V' { - 0 51 - 1 51 - 4 51 - 5 51 - 6 51 - 7 51 - 9 51 - a 52 + 0 46 + 1 46 + 4 46 + 5 46 + 6 46 + 7 46 + 9 46 + a 46 } } @@ -260,19 +254,19 @@ Lines mapping: 11 <-> 11 13 <-> 12 14 <-> 13 -19 <-> 19 -20 <-> 21 -24 <-> 25 -26 <-> 27 -27 <-> 28 -30 <-> 32 -31 <-> 34 -35 <-> 38 -37 <-> 40 -38 <-> 41 -39 <-> 42 -40 <-> 43 -42 <-> 44 -43 <-> 45 -49 <-> 52 -50 <-> 54 +19 <-> 18 +20 <-> 19 +24 <-> 23 +26 <-> 25 +27 <-> 26 +30 <-> 29 +31 <-> 30 +35 <-> 34 +37 <-> 36 +38 <-> 37 +39 <-> 38 +40 <-> 39 +42 <-> 40 +43 <-> 41 +49 <-> 47 +50 <-> 48 diff --git a/testData/src/java16/pkg/TestRecordBig.java b/testData/src/java16/pkg/TestRecordBig.java new file mode 100644 index 0000000000..e302b09fbd --- /dev/null +++ b/testData/src/java16/pkg/TestRecordBig.java @@ -0,0 +1,21 @@ +package pkg; + +public record TestRecordBig( + int comp1, + int comp2, + int comp3, + int comp4, + int comp5, + int comp6, + int comp7, + int comp8, + int comp9, + int comp10, + int comp11, + int comp12, + int comp13, + int comp14, + int comp15, + int comp16 +) { +} diff --git a/testData/src/java8/pkg/TestBinaryOperationWrapping.java b/testData/src/java8/pkg/TestBinaryOperationWrapping.java new file mode 100644 index 0000000000..9d19d2b2f9 --- /dev/null +++ b/testData/src/java8/pkg/TestBinaryOperationWrapping.java @@ -0,0 +1,14 @@ +package pkg; + +public class TestBinaryOperationWrapping { + public void testStringConcatenation(String longVariableName) { + System.out.println( + "This is a very very very very very very very very very very very very very very very long string" + + longVariableName + longVariableName + longVariableName + longVariableName + longVariableName + ); + } + + public void testBooleanOperation(boolean a, boolean b, boolean c, boolean d, boolean e, boolean f, boolean g, boolean h, boolean i, boolean j, boolean k, boolean l, boolean m, boolean n, boolean o, boolean p, boolean q, boolean r, boolean s, boolean t, boolean u, boolean v, boolean w, boolean x, boolean y, boolean z) { + System.out.println(a && b || c && d || e && f || g && h || i && j || k && l || m && n || o && p || q && r || s && t || u && v || w && x || y && z); + } +} diff --git a/testData/src/java8/pkg/TestLongMethodDeclaration.java b/testData/src/java8/pkg/TestLongMethodDeclaration.java new file mode 100644 index 0000000000..845ffd3d02 --- /dev/null +++ b/testData/src/java8/pkg/TestLongMethodDeclaration.java @@ -0,0 +1,22 @@ +package pkg; + +public class TestLongMethodDeclaration { + public void foo( + int param1, + int param2, + int param3, + int param4, + int param5, + int param6, + int param7, + int param8, + int param9, + int param10, + int param11, + int param12, + int param13, + int param14, + int param15, + int param16 + ) {} +} diff --git a/testData/src/java8/pkg/TestLongMethodInvocation.java b/testData/src/java8/pkg/TestLongMethodInvocation.java new file mode 100644 index 0000000000..00ccd43106 --- /dev/null +++ b/testData/src/java8/pkg/TestLongMethodInvocation.java @@ -0,0 +1,72 @@ +package pkg; + +public class TestLongMethodInvocation { + private TestLongMethodInvocation longField; + + public TestLongMethodInvocation longMethodInvocation() { + this.longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation() + .longMethodInvocation(); + return this; + } + + public void longFieldInvocation() { + this.longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longField + .longMethodInvocation(); + } + + public void longMixture() { + this.longField + .longMethodInvocation() + .longField + .longMethodInvocation() + .longField + .longMethodInvocation() + .longField + .longMethodInvocation() + .longField + .longMethodInvocation() + .longField + .longMethodInvocation() + .longField + .longMethodInvocation() + .longField + .longMethodInvocation(); + } +} From 91755ccc023cd194a447ae36d21e9a97db7a15b9 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Sun, 14 Nov 2021 17:54:28 -0800 Subject: [PATCH 09/85] Publish to snapshot repository --- .github/workflows/snapshot.yml | 17 +++++++++++++++++ build.gradle | 12 ++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 .github/workflows/snapshot.yml diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 0000000000..a3c5674a5c --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,17 @@ +name: Publish Snapshot +on: [push, pull_request] +jobs: + publish: + if: ${{ github.repository_owner == 'QuiltMC' && contains(github.ref_name, "develop") }} + runs-on: ubuntu-20.04 + container: + image: openjdk:15-jdk + options: --user root + steps: + - uses: actions/checkout@v1 + - uses: gradle/wrapper-validation-action@v1 + - run: ./gradlew publish --stacktrace + env: + SNAPSHOT_MAVEN_URL: ${{ secrets.SNAPSHOT_MAVEN_URL }} + SNAPSHOT_MAVEN_USERNAME: ${{ secrets.SNAPSHOT_MAVEN_USERNAME }} + SNAPSHOT_MAVEN_PASSWORD: ${{ secrets.SNAPSHOT_MAVEN_PASSWORD }} \ No newline at end of file diff --git a/build.gradle b/build.gradle index c956161298..2a1523d23d 100644 --- a/build.gradle +++ b/build.gradle @@ -139,6 +139,9 @@ publishing { publications { mavenJava(MavenPublication) { from components.java + if (ENV.SNAPSHOT_MAVEN_URL) { + version = project.version + "-SNAPSHOT" + } artifact(sourceJar) } } @@ -154,5 +157,14 @@ publishing { } } } + if (ENV.SNAPSHOT_MAVEN_URL) { + maven { + url ENV.SNAPSHOT_MAVEN_URL + credentials { + username ENV.SNAPSHOT_MAVEN_USERNAME + password ENV.SNAPSHOT_MAVEN_PASSWORD + } + } + } } } From 4058ad2d6255a46860a194a4001e9d34aac003e1 Mon Sep 17 00:00:00 2001 From: Eli Orona Date: Sun, 14 Nov 2021 17:56:20 -0800 Subject: [PATCH 10/85] use single quotes --- .github/workflows/snapshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index a3c5674a5c..26c7318828 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -2,7 +2,7 @@ name: Publish Snapshot on: [push, pull_request] jobs: publish: - if: ${{ github.repository_owner == 'QuiltMC' && contains(github.ref_name, "develop") }} + if: ${{ github.repository_owner == 'QuiltMC' && contains(github.ref_name, 'develop') }} runs-on: ubuntu-20.04 container: image: openjdk:15-jdk From cf160960f4d63d0371444b7a583893f864c9bd8e Mon Sep 17 00:00:00 2001 From: ByMartrixx Date: Sun, 14 Nov 2021 23:28:06 -0300 Subject: [PATCH 11/85] Use the correct secrets --- .github/workflows/snapshot.yml | 6 +++--- build.gradle | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 26c7318828..46380533f7 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -12,6 +12,6 @@ jobs: - uses: gradle/wrapper-validation-action@v1 - run: ./gradlew publish --stacktrace env: - SNAPSHOT_MAVEN_URL: ${{ secrets.SNAPSHOT_MAVEN_URL }} - SNAPSHOT_MAVEN_USERNAME: ${{ secrets.SNAPSHOT_MAVEN_USERNAME }} - SNAPSHOT_MAVEN_PASSWORD: ${{ secrets.SNAPSHOT_MAVEN_PASSWORD }} \ No newline at end of file + SNAPSHOT_URL: ${{ secrets.SNAPSHOT_URL }} + SNAPSHOT_USERNAME: ${{ secrets.SNAPSHOT_USERNAME }} + SNAPSHOT_PASSWORD: ${{ secrets.SNAPSHOT_PASSWORD }} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 2a1523d23d..696041aad8 100644 --- a/build.gradle +++ b/build.gradle @@ -139,7 +139,7 @@ publishing { publications { mavenJava(MavenPublication) { from components.java - if (ENV.SNAPSHOT_MAVEN_URL) { + if (ENV.SNAPSHOT_URL) { version = project.version + "-SNAPSHOT" } artifact(sourceJar) @@ -157,12 +157,12 @@ publishing { } } } - if (ENV.SNAPSHOT_MAVEN_URL) { + if (ENV.SNAPSHOT_URL) { maven { - url ENV.SNAPSHOT_MAVEN_URL + url ENV.SNAPSHOT_URL credentials { - username ENV.SNAPSHOT_MAVEN_USERNAME - password ENV.SNAPSHOT_MAVEN_PASSWORD + username ENV.SNAPSHOT_USERNAME + password ENV.SNAPSHOT_PASSWORD } } } From 6c6f7ab9e8e823d9e326d7d8764733ac0b2c6908 Mon Sep 17 00:00:00 2001 From: ByMartrixx Date: Sun, 14 Nov 2021 23:31:45 -0300 Subject: [PATCH 12/85] (Actually) use the correct secrets --- .github/workflows/snapshot.yml | 6 +++--- build.gradle | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 46380533f7..840f03dc68 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -12,6 +12,6 @@ jobs: - uses: gradle/wrapper-validation-action@v1 - run: ./gradlew publish --stacktrace env: - SNAPSHOT_URL: ${{ secrets.SNAPSHOT_URL }} - SNAPSHOT_USERNAME: ${{ secrets.SNAPSHOT_USERNAME }} - SNAPSHOT_PASSWORD: ${{ secrets.SNAPSHOT_PASSWORD }} \ No newline at end of file + SNAPSHOTS_URL: ${{ secrets.SNAPSHOTS_URL }} + SNAPSHOTS_USERNAME: ${{ secrets.SNAPSHOTS_USERNAME }} + SNAPSHOTS_PASSWORD: ${{ secrets.SNAPSHOTS_PASSWORD }} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 696041aad8..7a10a2bba1 100644 --- a/build.gradle +++ b/build.gradle @@ -139,7 +139,7 @@ publishing { publications { mavenJava(MavenPublication) { from components.java - if (ENV.SNAPSHOT_URL) { + if (ENV.SNAPSHOTS_URL) { version = project.version + "-SNAPSHOT" } artifact(sourceJar) @@ -157,12 +157,12 @@ publishing { } } } - if (ENV.SNAPSHOT_URL) { + if (ENV.SNAPSHOTS_URL) { maven { - url ENV.SNAPSHOT_URL + url ENV.SNAPSHOTS_URL credentials { - username ENV.SNAPSHOT_USERNAME - password ENV.SNAPSHOT_PASSWORD + username ENV.SNAPSHOTS_USERNAME + password ENV.SNAPSHOTS_PASSWORD } } } From 10dfd248ac2690aede830021e284a6e135cea4ba Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 16 Nov 2021 14:57:03 +0000 Subject: [PATCH 13/85] TextBuffer assertions --- .../java/decompiler/main/ClassWriter.java | 6 +- .../java/decompiler/main/Fernflower.java | 2 +- .../java/decompiler/main/RecordHelper.java | 6 +- .../modules/decompiler/exps/ConstExprent.java | 2 +- .../modules/decompiler/exps/Exprent.java | 2 +- .../modules/decompiler/exps/FieldExprent.java | 2 +- .../decompiler/exps/InvocationExprent.java | 2 +- .../java/decompiler/util/TextBuffer.java | 94 ++++++++++++++++++- .../decompiler/BulkDecompilationTest.java | 5 + .../decompiler/SingleClassesTestBase.java | 2 + 10 files changed, 110 insertions(+), 13 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 6ee438f77b..bc462df90a 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -1329,7 +1329,7 @@ static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, in StructAnnotationAttribute attribute = (StructAnnotationAttribute)mb.getAttribute(key); if (attribute != null) { for (AnnotationExprent annotation : attribute.getAnnotations()) { - String text = annotation.toJava(indent).toString(); + String text = annotation.toJava(indent).convertToStringAndAllowDataDiscard(); filter.add(text); buffer.append(text); if (indent < 0) { @@ -1400,7 +1400,7 @@ private static void appendParameterAnnotations(TextBuffer buffer, StructMethod m List> annotations = attribute.getParamAnnotations(); if (param < annotations.size()) { for (AnnotationExprent annotation : annotations.get(param)) { - String text = annotation.toJava(-1).toString(); + String text = annotation.toJava(-1).convertToStringAndAllowDataDiscard(); filter.add(text); buffer.append(text).append(' '); } @@ -1417,7 +1417,7 @@ private static void appendTypeAnnotations(TextBuffer buffer, int indent, StructM if (attribute != null) { for (TypeAnnotation annotation : attribute.getAnnotations()) { if (annotation.isTopLevel() && annotation.getTargetType() == targetType && (index < 0 || annotation.getIndex() == index)) { - String text = annotation.getAnnotation().toJava(indent).toString(); + String text = annotation.getAnnotation().toJava(indent).convertToStringAndAllowDataDiscard(); if (!filter.contains(text)) { buffer.append(text); if (indent < 0) { diff --git a/src/org/jetbrains/java/decompiler/main/Fernflower.java b/src/org/jetbrains/java/decompiler/main/Fernflower.java index 32df59a07a..3fa3f2e49a 100644 --- a/src/org/jetbrains/java/decompiler/main/Fernflower.java +++ b/src/org/jetbrains/java/decompiler/main/Fernflower.java @@ -147,7 +147,7 @@ public String getClassContent(StructClass cl) { TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE); buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString()); classProcessor.writeClass(cl, buffer); - return buffer.toString(); + return buffer.convertToStringAndAllowDataDiscard(); } catch (Throwable t) { DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", t); diff --git a/src/org/jetbrains/java/decompiler/main/RecordHelper.java b/src/org/jetbrains/java/decompiler/main/RecordHelper.java index 8867781f91..bb0ceab7c1 100644 --- a/src/org/jetbrains/java/decompiler/main/RecordHelper.java +++ b/src/org/jetbrains/java/decompiler/main/RecordHelper.java @@ -125,7 +125,7 @@ private static Set getRecordComponentAnnotations(StructClass cl, StructR StructAnnotationAttribute attribute = (StructAnnotationAttribute) member.getAttribute(key); if (attribute == null) continue; for (AnnotationExprent annotation : attribute.getAnnotations()) { - String text = annotation.toJava(-1).toString(); + String text = annotation.toJava(-1).convertToStringAndAllowDataDiscard(); annotations.add(text); } } @@ -137,7 +137,7 @@ private static Set getRecordComponentAnnotations(StructClass cl, StructR if (!annotation.isTopLevel()) continue; int type = annotation.getTargetType(); if (type == TypeAnnotation.FIELD || type == TypeAnnotation.METHOD_PARAMETER) { - String text = annotation.getAnnotation().toJava(-1).toString(); + String text = annotation.getAnnotation().toJava(-1).convertToStringAndAllowDataDiscard(); annotations.add(text); } } @@ -153,7 +153,7 @@ private static Set getRecordComponentAnnotations(StructClass cl, StructR List> paramAnnotations = attribute.getParamAnnotations(); if (param >= paramAnnotations.size()) continue; for (AnnotationExprent annotation : paramAnnotations.get(param)) { - String text = annotation.toJava(-1).toString(); + String text = annotation.toJava(-1).convertToStringAndAllowDataDiscard(); annotations.add(text); } } 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 a21a7b9323..5a51140191 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java @@ -531,7 +531,7 @@ public void getBytecodeRange(BitSet values) { @Override public String toString() { - return "const(" + toJava(0) + ")"; + return "const(" + toJava(0).convertToStringAndAllowDataDiscard() + ")"; } // ***************************************************************************** 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 cf6367186a..e508a606df 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java @@ -382,6 +382,6 @@ public boolean match(MatchNode matchNode, MatchEngine engine) { @Override public String toString() { - return toJava(0).toString(); + return toJava(0).convertToStringAndAllowDataDiscard(); } } \ No newline at end of file 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 2fd3b609e6..fb21cabf52 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -184,7 +184,7 @@ public TextBuffer toJava(int indent) { buf.append(buff); } - if (buf.toString().equals( + if (buf.contentEquals( VarExprent.VAR_NAMELESS_ENCLOSURE)) { // FIXME: workaround for field access of an anonymous enclosing class. Find a better way. buf.setLength(0); } 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 2a9978fb69..4d57980602 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -675,7 +675,7 @@ else if (JAVA_NIO_BUFFER.equals(descriptor.ret) && !JAVA_NIO_BUFFER.equals(right switch (functype) { case TYP_GENERAL: - if (VarExprent.VAR_NAMELESS_ENCLOSURE.equals(buf.toString())) { + if (buf.contentEquals(VarExprent.VAR_NAMELESS_ENCLOSURE)) { buf = new TextBuffer(); } diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index 134854ab51..61bdc68e69 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -5,9 +5,14 @@ import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; +import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; /** * Allows to connect text with resulting lines @@ -16,11 +21,14 @@ */ @SuppressWarnings("UnusedReturnValue") public class TextBuffer { + private static final boolean ALLOW_TO_STRING = Boolean.getBoolean("decompiler.allow.to.string"); + private final String myLineSeparator = DecompilerContext.getNewLineSeparator(); private final String myIndent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING); private final StringBuilder myStringBuilder; private Map myLineToOffsetMapping = null; private final Map myBytecodeOffsetMapping = new LinkedHashMap<>(); // bytecode offset -> offset in text + private final DebugTrace myDebugTrace = DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE) ? new DebugTrace(this) : null; public TextBuffer() { myStringBuilder = new StringBuilder(); @@ -83,10 +91,16 @@ public boolean containsOnlyWhitespaces() { } public void addBytecodeMapping(int bytecodeOffset) { + if (myDebugTrace != null) { + myDebugTrace.myPreventDeletion = true; + } myBytecodeOffsetMapping.putIfAbsent(new BytecodeMappingKey(bytecodeOffset, null, null), myStringBuilder.length()); } public void addStartBytecodeMapping(int bytecodeOffset) { + if (myDebugTrace != null) { + myDebugTrace.myPreventDeletion = true; + } myBytecodeOffsetMapping.putIfAbsent(new BytecodeMappingKey(bytecodeOffset, null, null), 0); } @@ -133,8 +147,12 @@ public Map, BytecodeMappingTracer> getTracers() { return tracers; } - @Override - public String toString() { + public boolean contentEquals(String string) { + return myStringBuilder.toString().equals(string); + } + + public String convertToStringAndAllowDataDiscard() { + myDebugTrace.myPreventDeletion = false; String original = myStringBuilder.toString(); if (myLineToOffsetMapping == null || myLineToOffsetMapping.isEmpty()) { if (myLineMapping != null) { @@ -176,6 +194,18 @@ public String toString() { } } + @Override + public String toString() { + if (!ALLOW_TO_STRING) { + if (DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE)) { + throw new AssertionError("Usage of TextBuffer.toString"); + } else { + DecompilerContext.getLogger().writeMessage("Usage of TextBuffer.toString", IFernflowerLogger.Severity.WARN); + } + } + return convertToStringAndAllowDataDiscard(); + } + private String addOriginalLineNumbers() { StringBuilder sb = new StringBuilder(); int lineStart = 0, lineEnd; @@ -244,6 +274,9 @@ public void setLength(int position) { } public TextBuffer append(TextBuffer buffer, String className, String methodKey) { + if (buffer.myDebugTrace != null) { + buffer.myDebugTrace.myPreventDeletion = false; + } if (buffer.myLineToOffsetMapping != null && !buffer.myLineToOffsetMapping.isEmpty()) { checkMapCreated(); for (Map.Entry entry : buffer.myLineToOffsetMapping.entrySet()) { @@ -379,4 +412,61 @@ public String toString() { return myClass + ":" + myMethod + ":" + myBytecodeOffset; } } + + public static void checkLeaks() { + DebugTrace.checkLeaks(); + } + + // it's really important that this class does not directly or indirectly reference the TextBuffer, or we will create memory leaks + static class DebugTrace extends WeakReference { + private static final Set ALL_REMAINING_TRACES = ConcurrentHashMap.newKeySet(); + + private static final AtomicBoolean STARTED = new AtomicBoolean(); + private static final ReferenceQueue REFERENCE_QUEUE = new ReferenceQueue<>(); + + private static void ensureStarted() { + if (!STARTED.getAndSet(true)) { + Thread cleaner = new Thread(() -> { + while (true) { + DebugTrace trace; + try { + trace = (DebugTrace) REFERENCE_QUEUE.remove(); + } catch (InterruptedException e) { + break; + } + trace.onDeletion(); + ALL_REMAINING_TRACES.remove(trace); + } + }); + cleaner.setName("TextBuffer debug cleaner"); + cleaner.setDaemon(true); + cleaner.start(); + } + } + + DebugTrace(TextBuffer buffer) { + super(buffer, REFERENCE_QUEUE); + ensureStarted(); + ALL_REMAINING_TRACES.add(this); + } + + final Throwable myCreationTrace = new Throwable(); + boolean myPreventDeletion = false; + + private void onDeletion() { + if (myPreventDeletion) { + throw new AssertionError( + "TextBuffer was garbage collected without being added to another TextBuffer, data loss occurred. See cause for the creation trace", + myCreationTrace + ); + } + } + + static void checkLeaks() { + for (DebugTrace trace : ALL_REMAINING_TRACES) { + trace.onDeletion(); + } + ALL_REMAINING_TRACES.clear(); + } + } } \ No newline at end of file diff --git a/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java b/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java index dfbcf86829..e9baa85bef 100644 --- a/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java +++ b/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java @@ -3,6 +3,7 @@ import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import org.jetbrains.java.decompiler.util.TextBuffer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -41,6 +42,8 @@ public void testDirectory() { decompiler.decompileContext(); assertFilesEqual(fixture.getTestDataDir().resolve("bulk"), fixture.getTargetDir()); + + TextBuffer.checkLeaks(); } @Test @@ -69,6 +72,8 @@ private void doTestJar(String name) { unpack(fixture.getTargetDir().resolve(jarName), unpacked); assertFilesEqual(fixture.getTestDataDir().resolve(name), unpacked); + + TextBuffer.checkLeaks(); } private static void unpack(Path archive, Path targetDir) { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java index 96d54447c6..a7061c943a 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java @@ -16,6 +16,7 @@ package org.jetbrains.java.decompiler; import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler; +import org.jetbrains.java.decompiler.util.TextBuffer; import org.junit.jupiter.api.*; import org.opentest4j.AssertionFailedError; @@ -214,6 +215,7 @@ public void run(String[] options) throws IOException { } } } + TextBuffer.checkLeaks(); fixture.tearDown(); } From d6b82ef255db772e7d01d1f6fb75b3bcb14f2651 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 16 Nov 2021 15:03:59 +0000 Subject: [PATCH 14/85] Move checkLeaks before other assertions so those errors show up first (they might be the cause of other errors) --- .../jetbrains/java/decompiler/BulkDecompilationTest.java | 8 ++++---- .../jetbrains/java/decompiler/SingleClassesTestBase.java | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java b/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java index e9baa85bef..58a163e5b5 100644 --- a/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java +++ b/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java @@ -41,9 +41,9 @@ public void testDirectory() { decompiler.addSource(classes.toFile()); decompiler.decompileContext(); - assertFilesEqual(fixture.getTestDataDir().resolve("bulk"), fixture.getTargetDir()); - TextBuffer.checkLeaks(); + + assertFilesEqual(fixture.getTestDataDir().resolve("bulk"), fixture.getTargetDir()); } @Test @@ -68,12 +68,12 @@ private void doTestJar(String name) { decompiler.addSource(fixture.getTestDataDir().resolve(jarName).toFile()); decompiler.decompileContext(); + TextBuffer.checkLeaks(); + Path unpacked = fixture.getTempDir().resolve("unpacked"); unpack(fixture.getTargetDir().resolve(jarName), unpacked); assertFilesEqual(fixture.getTestDataDir().resolve(name), unpacked); - - TextBuffer.checkLeaks(); } private static void unpack(Path archive, Path targetDir) { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java index a7061c943a..385f1e6cf3 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java @@ -189,6 +189,8 @@ public void run(String[] options) throws IOException { decompiler.decompileContext(); + TextBuffer.checkLeaks(); + String testFileName = classFile.getFileName().toString(); String testName = testFileName.substring(0, testFileName.length() - 6); Path decompiledFile = fixture.getTargetDir().resolve(testName + ".java"); @@ -215,7 +217,6 @@ public void run(String[] options) throws IOException { } } } - TextBuffer.checkLeaks(); fixture.tearDown(); } From 2d1a06086ceaa1cce7832792b334e85f6b2ea935 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 16 Nov 2021 15:08:52 +0000 Subject: [PATCH 15/85] Rename ALLOW_TO_STRING system property --- src/org/jetbrains/java/decompiler/util/TextBuffer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index 61bdc68e69..7f25310854 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -21,7 +21,7 @@ */ @SuppressWarnings("UnusedReturnValue") public class TextBuffer { - private static final boolean ALLOW_TO_STRING = Boolean.getBoolean("decompiler.allow.to.string"); + private static final boolean ALLOW_TO_STRING = Boolean.getBoolean("decompiler.allow.text.buffer.to.string"); private final String myLineSeparator = DecompilerContext.getNewLineSeparator(); private final String myIndent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING); From e6018633b4ac8606b0ced04c4d2c3411f4443c80 Mon Sep 17 00:00:00 2001 From: Simon Wanner Date: Tue, 16 Nov 2021 19:19:56 +0100 Subject: [PATCH 16/85] Don't mark implicitly sealed enums as sealed classes --- .../java/decompiler/main/ClassWriter.java | 4 +-- .../java/decompiler/SingleClassesTest.java | 2 ++ .../results/pkg/TestImplicitlySealedEnum.dec | 33 +++++++++++++++++++ .../java17/pkg/TestImplicitlySealedEnum.java | 14 ++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 testData/results/pkg/TestImplicitlySealedEnum.dec create mode 100644 testData/src/java17/pkg/TestImplicitlySealedEnum.java diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 6ee438f77b..c939883b65 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -479,7 +479,7 @@ private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) appendModifiers(buffer, flags, CLASS_ALLOWED, isInterface, CLASS_EXCLUDED); - if (isSealed) { + if (!isEnum && isSealed) { buffer.append("sealed "); } else if (isNonSealed) { buffer.append("non-sealed "); @@ -547,7 +547,7 @@ else if (components != null) { } } - if (isSealed) { + if (!isEnum && isSealed) { buffer.append("permits "); for (int i = 0; i < permittedSubClasses.size(); i++) { if (i > 0) { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index e4d23e7fa7..26be6cfc44 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -375,6 +375,8 @@ private void registerDefault() { register(JAVA_8, "TestUnicodeIdentifiers"); register(JAVA_8, "TestDoubleBraceInitializers"); + + register(JAVA_17, "TestImplicitlySealedEnum"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestImplicitlySealedEnum.dec b/testData/results/pkg/TestImplicitlySealedEnum.dec new file mode 100644 index 0000000000..83be254bee --- /dev/null +++ b/testData/results/pkg/TestImplicitlySealedEnum.dec @@ -0,0 +1,33 @@ +package pkg; + +public enum TestImplicitlySealedEnum { + A, + B { + @Override + int getX() { + return 2;// 7 + } + }; + + int getX() { + return 1;// 12 + } +} + +class 'pkg/TestImplicitlySealedEnum$1' { + method 'getX ()I' { + 0 7 + 1 7 + } +} + +class 'pkg/TestImplicitlySealedEnum' { + method 'getX ()I' { + 0 12 + 1 12 + } +} + +Lines mapping: +7 <-> 8 +12 <-> 13 diff --git a/testData/src/java17/pkg/TestImplicitlySealedEnum.java b/testData/src/java17/pkg/TestImplicitlySealedEnum.java new file mode 100644 index 0000000000..53f2330831 --- /dev/null +++ b/testData/src/java17/pkg/TestImplicitlySealedEnum.java @@ -0,0 +1,14 @@ +package pkg; + +public enum TestImplicitlySealedEnum { + A, B { + @Override + int getX() { + return 2; + } + }; + + int getX() { + return 1; + } +} From ee1b5b2e44e64fd78c68bb64839949e9b76cf0a2 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 16 Nov 2021 16:43:32 -0500 Subject: [PATCH 17/85] Add initial switch expression implementation --- .../java/decompiler/code/BytecodeVersion.java | 4 + .../main/extern/IFernflowerPreferences.java | 4 + .../main/rels/MethodProcessorRunnable.java | 19 ++ .../modules/decompiler/ExprProcessor.java | 4 +- .../decompiler/SimplifyExprentsHelper.java | 2 +- .../decompiler/SwitchExpressionHelper.java | 132 ++++++++++++ .../modules/decompiler/SwitchHelper.java | 12 +- .../decompiler/exps/AnnotationExprent.java | 11 + .../decompiler/exps/AssertExprent.java | 5 + .../modules/decompiler/exps/Exprent.java | 12 +- .../decompiler/exps/SwitchExprent.java | 198 ++++++++++-------- .../decompiler/exps/SwitchHeadExprent.java | 125 +++++++++++ .../modules/decompiler/exps/YieldExprent.java | 54 +++++ .../decompiler/stats/BasicBlockStatement.java | 9 + .../decompiler/stats/SwitchStatement.java | 39 +++- .../decompiler/struct/match/MatchEngine.java | 2 +- .../java/decompiler/SingleClassesTest.java | 1 + .../pkg/TestAssignmentSwitchExpression1.dec | 186 +++++++--------- .../pkg/TestAssignmentSwitchExpression2.dec | 86 +++----- .../pkg/TestAssignmentSwitchExpression3.dec | 138 ++++++------ .../pkg/TestAssignmentSwitchExpression4.dec | 103 ++++----- .../pkg/TestAssignmentSwitchExpression5.dec | 103 ++++----- .../pkg/TestAssignmentSwitchExpression7.dec | 41 ++++ .../pkg/TestConstructorSwitchExpression1.dec | 74 +++---- .../pkg/TestInlineSwitchExpression1.dec | 99 ++++----- .../pkg/TestInlineSwitchExpression3.dec | 49 ++--- .../pkg/TestReturnSwitchExpression1.dec | 44 ++-- .../pkg/TestReturnSwitchExpression2.dec | 42 ++-- .../pkg/TestReturnSwitchExpression3.dec | 39 ++-- .../TestSwitchPatternMatchingConstructor2.dec | 84 ++++---- .../pkg/TestSwitchPatternMatchingReturn1.dec | 35 ++-- .../pkg/TestAssignmentSwitchExpression7.java | 12 ++ .../pkg/TestInlineSwitchExpression3.java | 2 + 33 files changed, 1025 insertions(+), 745 deletions(-) create mode 100644 src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java create mode 100644 src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java create mode 100644 src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java create mode 100644 testData/results/pkg/TestAssignmentSwitchExpression7.dec create mode 100644 testData/src/java16/pkg/TestAssignmentSwitchExpression7.java diff --git a/src/org/jetbrains/java/decompiler/code/BytecodeVersion.java b/src/org/jetbrains/java/decompiler/code/BytecodeVersion.java index 82a398c233..b3c1431874 100644 --- a/src/org/jetbrains/java/decompiler/code/BytecodeVersion.java +++ b/src/org/jetbrains/java/decompiler/code/BytecodeVersion.java @@ -33,6 +33,10 @@ public boolean hasIfPatternMatching() { return major >= MAJOR_16; } + public boolean hasSwitchExpressions() { + return major >= MAJOR_16; + } + public boolean hasSealedClasses() { return previewReleased(MAJOR_15, MAJOR_17); } diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java index 59ae1f64f0..6c89a9ecdd 100644 --- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java +++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java @@ -38,6 +38,8 @@ public interface IFernflowerPreferences { String PATTERN_MATCHING = "pam"; String EXPERIMENTAL_TRY_LOOP_FIX = "tlf"; String TERNARY_CONDITIONS = "tco"; + String SWITCH_EXPRESSIONS = "swe"; + String SHOW_HIDDEN_STATEMENTS = "shs"; String INCLUDE_ENTIRE_CLASSPATH = "iec"; String INCLUDE_JAVA_RUNTIME = "jrt"; @@ -102,6 +104,8 @@ static Map getDefaults() { defaults.put(PATTERN_MATCHING, "0"); // Pattern matching has some issues around negative blocks defaults.put(EXPERIMENTAL_TRY_LOOP_FIX, "0"); // Causes issues when decompiling certain classes defaults.put(TERNARY_CONDITIONS, "1"); // Ternary conditions are pretty stable so they can go in here + defaults.put(SWITCH_EXPRESSIONS, "1"); // While still experimental, switch expressions work pretty well + defaults.put(SHOW_HIDDEN_STATEMENTS, "0"); // Extra debugging that isn't useful in most cases defaults.put(INCLUDE_ENTIRE_CLASSPATH, "0"); defaults.put(INCLUDE_JAVA_RUNTIME, "0"); diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java index bba0f9b148..f1a5009ce3 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java +++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java @@ -259,9 +259,17 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe } } + if (SwitchExpressionHelper.hasSwitchExpressions(root)) { + if (SwitchExpressionHelper.processSwitchExpressions(root)) { + decompileRecord.add("ProcessSwitchExpr", root); + continue; + } + } + LabelHelper.identifyLabels(root); decompileRecord.add("IdentifyLabels", root); + // TODO: should be done before label identification but that causes issues with old style J8 try with resources being enclosed in a label when it shouldn't be if (TryHelper.enhanceTryStats(root, cl)) { decompileRecord.add("EnhanceTry", root); continue; @@ -304,6 +312,17 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe SequenceHelper.condenseSequences(root); // remove empty blocks decompileRecord.add("CondenseSequences_SS", root); + + if (SwitchExpressionHelper.hasSwitchExpressions(root)) { + // Make last minute switch expressions + if (SwitchExpressionHelper.processSwitchExpressions(root)) { + decompileRecord.add("ProcessSwitchExpr_SS", root); + + // Simplify stack vars to integrate and inline switch expressions + stackProc.simplifyStackVars(root, mt, cl); + decompileRecord.add("SimplifyStackVars_SS", root); + } + } } // Makes constant returns the same type as the method descriptor diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java index 9f0a721294..4cc5f4927b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java @@ -504,7 +504,7 @@ else if (cn instanceof LinkConstant) { break; case opc_tableswitch: case opc_lookupswitch: - exprlist.add(new SwitchExprent(stack.pop(), bytecode_offsets)); + exprlist.add(new SwitchHeadExprent(stack.pop(), bytecode_offsets)); break; case opc_ireturn: case opc_lreturn: @@ -775,7 +775,7 @@ public static PrimitiveExprsList getExpressionData(VarExprent var) { public static boolean endsWithSemicolon(Exprent expr) { int type = expr.type; - return !(type == Exprent.EXPRENT_SWITCH || + return !(type == Exprent.EXPRENT_SWITCH_HEAD || type == Exprent.EXPRENT_MONITOR || type == Exprent.EXPRENT_IF || (type == Exprent.EXPRENT_VAR && ((VarExprent)expr).isClassDef())); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java index bf02f4b516..240cbf98b7 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java @@ -357,7 +357,7 @@ private static boolean isAssignmentReturn(Exprent first, Exprent second) { VarExprent assignmentLeft = (VarExprent) assignment.getLeft(); VarExprent exitValue = (VarExprent) exit.getValue(); //If the assignment before the return is immediately used in the return, inline it. - if (assignmentLeft.equals(exitValue) && !assignmentLeft.isStack() && !exitValue.isStack()) { + if (assignmentLeft.equals(exitValue) && ((!assignmentLeft.isStack() && !exitValue.isStack()) || assignment.getRight().type == Exprent.EXPRENT_SWITCH)) { exit.replaceExprent(exitValue, assignment.getRight()); return true; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java new file mode 100644 index 0000000000..f2cfbcc9eb --- /dev/null +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java @@ -0,0 +1,132 @@ +package org.jetbrains.java.decompiler.modules.decompiler; + +import org.jetbrains.java.decompiler.main.DecompilerContext; +import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import org.jetbrains.java.decompiler.modules.decompiler.exps.*; +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.SwitchStatement; +import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class SwitchExpressionHelper { + public static boolean processSwitchExpressions(Statement stat) { + boolean ret = false; + for (Statement st : stat.getStats()) { + ret |= processSwitchExpressions(st); + } + + if (stat.type == Statement.TYPE_SWITCH) { + ret |= processStatement((SwitchStatement) stat); + } + + return ret; + } + + private static boolean processStatement(SwitchStatement stat) { + if (stat.isPhantom()) { + return false; + } + + // At this stage, there are no variable assignments + // So we need to figure out which variable, if any, this switch statement is an expression of and make it generate. + + VarVersionPair foundVar = null; + VarExprent found = null; + for (Statement caseStat : stat.getCaseStatements()) { + // Need to be basic blocks for now + if (caseStat.type != Statement.TYPE_BASICBLOCK) { + return false; + } + + List exprents = caseStat.getExprents(); + if (exprents != null && !exprents.isEmpty()) { + Exprent exprent = exprents.get(exprents.size() - 1); + + if (exprent.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)exprent).getLeft().type == Exprent.EXPRENT_VAR) { + VarVersionPair var = (((VarExprent) ((AssignmentExprent) exprent).getLeft())).getVarVersionPair(); + + if (foundVar == null) { + foundVar = var; + found = (((VarExprent) ((AssignmentExprent) exprent).getLeft())); + } else { + if (!foundVar.equals(var)) { + return false; + } + } + } else if (exprent.type == Exprent.EXPRENT_EXIT && ((ExitExprent)exprent).getExitType() == ExitExprent.EXIT_RETURN) { + // TODO: check for successors to dummy exit! + return false; // Has a return, cannot be a switch statement + } + } + } + + if (foundVar == null || found == null) { + return false; + } + + List sucs = stat.getSuccessorEdges(StatEdge.TYPE_REGULAR); + + // TODO: should we be using getbasichead? + if (!sucs.isEmpty()) { + + Statement suc = sucs.get(0).getDestination(); + if (suc.type == Statement.TYPE_BASICBLOCK) { // TODO: make basic block if it isn't found + stat.setPhantom(true); + + for (Statement st : stat.getCaseStatements()) { + Map replacements = new HashMap<>(); + + // No exprents, must not be a basicblock + if (st.getExprents() == null) { + continue; + } + + for (Exprent e : st.getExprents()) { + // Check for "var10000 = " within the exprents + if (e.type == Exprent.EXPRENT_ASSIGNMENT) { + AssignmentExprent assign = ((AssignmentExprent) e); + + if (assign.getLeft().type == Exprent.EXPRENT_VAR) { + if (((VarExprent)assign.getLeft()).getIndex() == foundVar.var) { + // Make yield with the right side of the assignment + replacements.put(assign, new YieldExprent(assign.getRight(), assign.getExprType())); + } + } + } + } + + // Replace exprents that we found + if (!replacements.isEmpty()) { + // Replace the assignments with yields, this allows 2 things: + // 1) + for (Map.Entry entry : replacements.entrySet()) { + st.replaceExprent(entry.getKey(), entry.getValue()); + } + } + } + + // TODO: move exprents from switch head to successor + + List exprents = suc.getExprents(); + + VarExprent vExpr = new VarExprent(found.getIndex(), found.getVarType(), found.getProcessor()); + vExpr.setStack(true); // We want to inline + AssignmentExprent toAdd = new AssignmentExprent(vExpr, new SwitchExprent(stat, found.getExprType()), null); + + exprents.add(0, toAdd); + + return true; + } + } + + return false; + } + + public static boolean hasSwitchExpressions(RootStatement statement) { + return statement.mt.getBytecodeVersion().hasSwitchExpressions() && DecompilerContext.getOption(IFernflowerPreferences.SWITCH_EXPRESSIONS); + } +} diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java index 2c03044ae8..e91343a9e1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java @@ -41,8 +41,8 @@ private static boolean simplify(SwitchStatement switchStatement, StructMethod mt following = (SwitchStatement)edges.get(0).getDestination(); } - SwitchExprent switchExprent = (SwitchExprent)switchStatement.getHeadexprent(); - Exprent value = switchExprent.getValue(); + SwitchHeadExprent switchHeadExprent = (SwitchHeadExprent)switchStatement.getHeadexprent(); + Exprent value = switchHeadExprent.getValue(); if (isEnumArray(value)) { List> caseValues = switchStatement.getCaseValues(); Map mapping = new HashMap<>(caseValues.size()); @@ -90,7 +90,7 @@ private static boolean simplify(SwitchStatement switchStatement, StructMethod mt } caseValues.clear(); caseValues.addAll(realCaseValues); - switchExprent.replaceExprent(value, ((InvocationExprent)array.getIndex()).getInstance().copy()); + switchHeadExprent.replaceExprent(value, ((InvocationExprent)array.getIndex()).getInstance().copy()); return true; } else if (isSwitchOnString(switchStatement, following)) { @@ -129,7 +129,7 @@ else if (isSwitchOnString(switchStatement, following)) { following.getCaseValues().clear(); following.getCaseValues().addAll(realCaseValues); - Exprent followingVal = ((SwitchExprent)following.getHeadexprent()).getValue(); + Exprent followingVal = ((SwitchHeadExprent)following.getHeadexprent()).getValue(); following.getHeadexprent().replaceExprent(followingVal, ((InvocationExprent)value).getInstance()); switchStatement.getFirst().getExprents().remove(switchStatement.getFirst().getExprents().size() - 1); @@ -224,8 +224,8 @@ private static boolean isEnumArray(Exprent exprent) { */ private static boolean isSwitchOnString(SwitchStatement first, SwitchStatement second) { if (second != null) { - Exprent firstValue = ((SwitchExprent)first.getHeadexprent()).getValue(); - Exprent secondValue = ((SwitchExprent)second.getHeadexprent()).getValue(); + Exprent firstValue = ((SwitchHeadExprent)first.getHeadexprent()).getValue(); + Exprent secondValue = ((SwitchHeadExprent)second.getHeadexprent()).getValue(); if (firstValue.type == Exprent.EXPRENT_INVOCATION && secondValue.type == Exprent.EXPRENT_VAR && first.getCaseStatements().get(0).type == Statement.TYPE_IF) { InvocationExprent invExpr = (InvocationExprent)firstValue; 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 df0898d64a..84d99681a8 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java @@ -9,6 +9,7 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.TextBuffer; +import java.util.ArrayList; import java.util.BitSet; import java.util.List; @@ -35,6 +36,16 @@ protected List getAllExprents(List list) { return list; } + @Override + public Exprent copy() { + List exps = new ArrayList<>(); + for (Exprent v : this.parValues) { + exps.add(v.copy()); + } + + return new AnnotationExprent(className, parNames, exps); + } + @Override public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buffer = new TextBuffer(); 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 34d99a1369..582de95471 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java @@ -24,6 +24,11 @@ protected List getAllExprents(List list) { return list; } + @Override + public Exprent copy() { + return null; + } + @Override public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buffer = new TextBuffer(); 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 035d738d45..61ccada2d1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java @@ -50,10 +50,12 @@ public abstract class Exprent implements IMatchable { public static final int EXPRENT_INVOCATION = 8; public static final int EXPRENT_MONITOR = 9; public static final int EXPRENT_NEW = 10; - public static final int EXPRENT_SWITCH = 11; + public static final int EXPRENT_SWITCH_HEAD = 11; public static final int EXPRENT_VAR = 12; public static final int EXPRENT_ANNOTATION = 13; public static final int EXPRENT_ASSERT = 14; + public static final int EXPRENT_SWITCH = 15; + public static final int EXPRENT_YIELD = 15; protected static ThreadLocal> inferredLambdaTypes = ThreadLocal.withInitial(HashMap::new); @@ -145,17 +147,13 @@ public final List getAllExprents() { // Preconditions: this list must never be removed from! Only added to! protected abstract List getAllExprents(List list); - public Exprent copy() { - throw new RuntimeException("not implemented"); - } + public abstract Exprent copy(); public TextBuffer toJava() { return toJava(0, BytecodeMappingTracer.DUMMY); } - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - throw new RuntimeException("not implemented"); - } + public abstract TextBuffer toJava(int indent, BytecodeMappingTracer tracer); public void replaceExprent(Exprent oldExpr, Exprent newExpr) { } 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 303a1c53c2..d3f8fc053f 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -1,125 +1,155 @@ -/* - * 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.exps; import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; -import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; +import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; +import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; +import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.SwitchStatement; import org.jetbrains.java.decompiler.struct.gen.VarType; -import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.TextBuffer; -import java.util.ArrayList; import java.util.BitSet; import java.util.List; public class SwitchExprent extends Exprent { + private final SwitchStatement backing; + private final VarType type; - private Exprent value; - private List> caseValues = new ArrayList<>(); - - public SwitchExprent(Exprent value, BitSet bytecodeOffsets) { + public SwitchExprent(SwitchStatement backing, VarType type) { super(EXPRENT_SWITCH); - this.value = value; - - addBytecodeOffsets(bytecodeOffsets); + this.backing = backing; + this.type = type; } @Override - public Exprent copy() { - SwitchExprent swExpr = new SwitchExprent(value.copy(), bytecode); - - List> lstCaseValues = new ArrayList<>(); - for (List lst : caseValues) { - lstCaseValues.add(new ArrayList<>(lst)); + public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + // Validity checks + if (!this.backing.isPhantom()) { + throw new IllegalStateException("Switch expression backing statement isn't phantom!"); } - swExpr.setCaseValues(lstCaseValues); - return swExpr; - } + TextBuffer buf = new TextBuffer(); - @Override - public VarType getExprType() { - return value.getExprType(); - } + VarType switchType = this.backing.getHeadexprentList().get(0).getExprType(); - @Override - public CheckTypesResult checkExprTypeBounds() { - CheckTypesResult result = new CheckTypesResult(); - - result.addMinTypeExprent(value, VarType.VARTYPE_BYTECHAR); - result.addMaxTypeExprent(value, VarType.VARTYPE_INT); - - VarType valType = value.getExprType(); - for (List lst : caseValues) { - for (Exprent expr : lst) { - if (expr != null) { - VarType caseType = expr.getExprType(); - if (!caseType.equals(valType)) { - valType = VarType.getCommonSupertype(caseType, valType); - result.addMinTypeExprent(value, valType); + buf.append(this.backing.getHeadexprentList().get(0).toJava(indent, tracer)).append(" {").appendLineSeparator(); + tracer.incrementCurrentSourceLine(); + for (int i = 0; i < this.backing.getCaseStatements().size(); i++) { + + Statement stat = this.backing.getCaseStatements().get(i); + List edges = this.backing.getCaseEdges().get(i); + List values = this.backing.getCaseValues().get(i); + + boolean hasDefault = false; + // As switch expressions can be compiled to a tableswitch, any gaps will contain a jump to the default element. + // Switch expressions cannot have a case point to the same statement as the default, so we check for default first and don't check for cases if it exists [TestConstructorSwitchExpression1] + + // TODO: exhaustive switch on enum has a synthetic default edge of throw new IncompatibleClassChangeException() + for (StatEdge edge : edges) { + if (edge == this.backing.getDefaultEdge()) { + buf.appendIndent(indent + 1).append("default -> "); + hasDefault = true; + break; + } + } + + boolean hasEdge = false; + if (!hasDefault) { + for (int j = 0; j < edges.size(); j++) { + Exprent value = values.get(j); + if (value == null) { // TODO: how can this be null? Is it trying to inject a synthetic case value in switch-on-string processing? [TestSwitchDefaultBefore] + continue; + } + + if (!hasEdge) { + buf.appendIndent(indent + 1).append("case "); + } else { + buf.append(", "); + } + + if (value instanceof ConstExprent) { + value = value.copy(); + ((ConstExprent)value).setConstType(switchType); + } + if (value instanceof FieldExprent && ((FieldExprent)value).isStatic()) { // enum values + buf.append(((FieldExprent)value).getName()); + } + else { + buf.append(value.toJava(indent, tracer)); + } + + hasEdge = true; + } + } + + if (hasEdge) { + buf.append(" -> "); + } + + boolean simple = true; + if (stat.type != Statement.TYPE_BASICBLOCK) { + simple = false; + } + + if (stat.getExprents() != null && stat.getExprents().size() != 1) { + simple = false; + } + + if (simple) { + Exprent exprent = stat.getExprents().get(0); + + if (exprent.type == Exprent.EXPRENT_YIELD) { + Exprent content = ((YieldExprent) exprent).getContent(); + + if (content.type == Exprent.EXPRENT_CONST) { + ((ConstExprent)content).setConstType(this.type); + } + + buf.append(content.toJava(indent, tracer).append(";")); + } else if (exprent.type == Exprent.EXPRENT_EXIT) { + ExitExprent exit = (ExitExprent) exprent; + + if (exit.getExitType() == ExitExprent.EXIT_THROW) { + buf.append(exit.toJava(indent, tracer).append(";")); + } else { + throw new IllegalStateException("Can't have return in switch expression"); } } + } else { + buf.append("{"); + buf.appendLineSeparator(); + tracer.incrementCurrentSourceLine(); + TextBuffer statBuf = stat.toJava(indent + 2, tracer); + buf.append(statBuf); + buf.appendIndent(indent + 1).append("}"); } + + buf.appendLineSeparator(); + tracer.incrementCurrentSourceLine(); } - return result; - } + buf.appendIndent(indent).append("}"); - @Override - public List getAllExprents(List lst) { - lst.add(value); - return lst; + return buf; } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - tracer.addMapping(bytecode); - return value.toJava(indent, tracer).enclose("switch(", ")"); + public VarType getExprType() { + return this.type; } @Override - public void replaceExprent(Exprent oldExpr, Exprent newExpr) { - if (oldExpr == value) { - value = newExpr; - } + public Exprent copy() { + return new SwitchExprent(this.backing, this.type); } @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (!(o instanceof SwitchExprent)) { - return false; - } - - SwitchExprent sw = (SwitchExprent)o; - return InterpreterUtil.equalObjects(value, sw.getValue()); + protected List getAllExprents(List list) { + return list; } @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; - } - public void setCaseValues(List> caseValues) { - this.caseValues = caseValues; } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java new file mode 100644 index 0000000000..48e117f7df --- /dev/null +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java @@ -0,0 +1,125 @@ +/* + * 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.exps; + +import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; +import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; +import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.util.InterpreterUtil; +import org.jetbrains.java.decompiler.util.TextBuffer; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; + +public class SwitchHeadExprent extends Exprent { + + private Exprent value; + private List> caseValues = new ArrayList<>(); + + public SwitchHeadExprent(Exprent value, BitSet bytecodeOffsets) { + super(EXPRENT_SWITCH_HEAD); + this.value = value; + + addBytecodeOffsets(bytecodeOffsets); + } + + @Override + public Exprent copy() { + SwitchHeadExprent swExpr = new SwitchHeadExprent(value.copy(), bytecode); + + List> lstCaseValues = new ArrayList<>(); + for (List lst : caseValues) { + lstCaseValues.add(new ArrayList<>(lst)); + } + swExpr.setCaseValues(lstCaseValues); + + return swExpr; + } + + @Override + public VarType getExprType() { + return value.getExprType(); + } + + @Override + public CheckTypesResult checkExprTypeBounds() { + CheckTypesResult result = new CheckTypesResult(); + + result.addMinTypeExprent(value, VarType.VARTYPE_BYTECHAR); + result.addMaxTypeExprent(value, VarType.VARTYPE_INT); + + VarType valType = value.getExprType(); + for (List lst : caseValues) { + for (Exprent expr : lst) { + if (expr != null) { + VarType caseType = expr.getExprType(); + if (!caseType.equals(valType)) { + valType = VarType.getCommonSupertype(caseType, valType); + result.addMinTypeExprent(value, valType); + } + } + } + } + + return result; + } + + @Override + public List getAllExprents(List lst) { + lst.add(value); + return lst; + } + + @Override + public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + tracer.addMapping(bytecode); + return value.toJava(indent, tracer).enclose("switch(", ")"); + } + + @Override + public void replaceExprent(Exprent oldExpr, Exprent newExpr) { + if (oldExpr == value) { + value = newExpr; + } + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof SwitchHeadExprent)) { + return false; + } + + SwitchHeadExprent sw = (SwitchHeadExprent)o; + return InterpreterUtil.equalObjects(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; + } + + public void setCaseValues(List> caseValues) { + this.caseValues = caseValues; + } +} diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java new file mode 100644 index 0000000000..d36cd08d78 --- /dev/null +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java @@ -0,0 +1,54 @@ +package org.jetbrains.java.decompiler.modules.decompiler.exps; + +import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; +import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; +import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.util.TextBuffer; + +import java.util.BitSet; +import java.util.List; + +public class YieldExprent extends Exprent { + private final Exprent content; + private final VarType retType; + + public YieldExprent(Exprent content, VarType retType) { + super(EXPRENT_YIELD); + this.content = content; + this.retType = retType; + } + + @Override + protected List getAllExprents(List list) { + list.add(this.content); + return list; + } + + @Override + public Exprent copy() { + return new YieldExprent(this.content.copy(), this.retType); + } + + @Override + public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + TextBuffer buf = new TextBuffer(); + buf.append("yield "); + ExprProcessor.getCastedExprent(this.content, this.retType, buf, indent, false, false, false, false, tracer); + + return buf; + } + + public Exprent getContent() { + return content; + } + + @Override + public VarType getExprType() { + return this.retType; + } + + @Override + public void getBytecodeRange(BitSet values) { + + } +} 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 b597fed7f2..26929882e2 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java @@ -117,6 +117,15 @@ public BasicBlock getBlock() { return block; } + @Override + public void replaceExprent(Exprent oldexpr, Exprent newexpr) { + for (int i = 0; i < this.exprents.size(); i++) { + if (this.exprents.get(i) == oldexpr) { + this.exprents.set(i, newexpr); + } + } + } + @Override public StartEndPair getStartEndRange() { if (block.size() > 0) { 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 40c72e6ad7..fef77fe9f4 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java @@ -6,13 +6,11 @@ import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.collectors.CounterContainer; +import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; -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.FieldExprent; -import org.jetbrains.java.decompiler.modules.decompiler.exps.SwitchExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.TextBuffer; import org.jetbrains.java.decompiler.util.StartEndPair; @@ -39,6 +37,11 @@ public final class SwitchStatement extends Statement { // constructors // ***************************************************************************** + // Phantom when converted to a switch expression. Spooky! + // We need to do this because switch expressions can have code in their case values, so we need to preserve the statement graph. + // The resulting statement isn't shown in the actual decompile (unless enabled specifically!) + private boolean phantom; + private SwitchStatement() { type = TYPE_SWITCH; @@ -110,12 +113,24 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer)); buf.append(first.toJava(indent, tracer)); + boolean showPhantom = DecompilerContext.getOption(IFernflowerPreferences.SHOW_HIDDEN_STATEMENTS); + + // Is phantom and we don't want to show- just return what we have so far + if (this.isPhantom() && !showPhantom) { + return buf; + } + if (isLabeled()) { buf.appendIndent(indent).append("label").append(this.id.toString()).append(":").appendLineSeparator(); tracer.incrementCurrentSourceLine(); } - buf.appendIndent(indent).append(headexprent.get(0).toJava(indent, tracer)).append(" {").appendLineSeparator(); + buf.appendIndent(indent); + if (this.isPhantom()) { + buf.append("/*"); + } + + buf.append(headexprent.get(0).toJava(indent, tracer)).append(" {").appendLineSeparator(); tracer.incrementCurrentSourceLine(); VarType switch_type = headexprent.get(0).getExprType(); @@ -160,12 +175,16 @@ public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { buf.appendIndent(indent).append("}").appendLineSeparator(); tracer.incrementCurrentSourceLine(); + if (this.isPhantom()) { + buf.append("*/"); + } + return buf; } @Override public void initExprents() { - SwitchExprent swexpr = (SwitchExprent)first.getExprents().remove(first.getExprents().size() - 1); + SwitchHeadExprent swexpr = (SwitchHeadExprent)first.getExprents().remove(first.getExprents().size() - 1); swexpr.setCaseValues(caseValues); headexprent.set(0, swexpr); @@ -394,4 +413,12 @@ public StatEdge getDefaultEdge() { public List> getCaseValues() { return caseValues; } + + public boolean isPhantom() { + return phantom; + } + + public void setPhantom(boolean phantom) { + this.phantom = phantom; + } } diff --git a/src/org/jetbrains/java/decompiler/struct/match/MatchEngine.java b/src/org/jetbrains/java/decompiler/struct/match/MatchEngine.java index 0eebccfa13..53d35032eb 100644 --- a/src/org/jetbrains/java/decompiler/struct/match/MatchEngine.java +++ b/src/org/jetbrains/java/decompiler/struct/match/MatchEngine.java @@ -60,7 +60,7 @@ public class MatchEngine { expr_type.put("invocation", Exprent.EXPRENT_INVOCATION); expr_type.put("monitor", Exprent.EXPRENT_MONITOR); expr_type.put("new", Exprent.EXPRENT_NEW); - expr_type.put("switch", Exprent.EXPRENT_SWITCH); + expr_type.put("switchhead", Exprent.EXPRENT_SWITCH_HEAD); expr_type.put("var", Exprent.EXPRENT_VAR); expr_type.put("annotation", Exprent.EXPRENT_ANNOTATION); expr_type.put("assert", Exprent.EXPRENT_ASSERT); diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index e4d23e7fa7..a667b6d46b 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -297,6 +297,7 @@ private void registerDefault() { register(JAVA_16, "TestAssignmentSwitchExpression4"); register(JAVA_16, "TestAssignmentSwitchExpression5"); register(JAVA_16, "TestAssignmentSwitchExpression6"); + register(JAVA_16, "TestAssignmentSwitchExpression7"); register(JAVA_16, "TestInlineSwitchExpression1"); register(JAVA_16, "TestInlineSwitchExpression2"); register(JAVA_16, "TestInlineSwitchExpression3"); diff --git a/testData/results/pkg/TestAssignmentSwitchExpression1.dec b/testData/results/pkg/TestAssignmentSwitchExpression1.dec index 7de2ed7762..305e62e77e 100644 --- a/testData/results/pkg/TestAssignmentSwitchExpression1.dec +++ b/testData/results/pkg/TestAssignmentSwitchExpression1.dec @@ -2,126 +2,86 @@ package pkg; public class TestAssignmentSwitchExpression1 { public void test(int x) { - String var10000; - switch(x) {// 5 - case 1: - var10000 = "January";// 6 - break; - case 2: - var10000 = "February";// 7 - break; - case 3: - var10000 = "March";// 8 - break; - case 4: - var10000 = "April";// 9 - break; - case 5: - var10000 = "May";// 10 - break; - case 6: - var10000 = "June";// 11 - break; - case 7: - var10000 = "July";// 12 - break; - case 8: - var10000 = "August";// 13 - break; - case 9: - var10000 = "September";// 14 - break; - case 10: - var10000 = "October";// 15 - break; - case 11: - var10000 = "November";// 16 - break; - case 12: - var10000 = "December";// 17 - break; - default: - throw new IllegalStateException("Unexpected value: " + x);// 18 - } - - String month = var10000; + String month = switch(x) {// 5 + case 1 -> "January";// 6 + case 2 -> "February";// 7 + case 3 -> "March";// 8 + case 4 -> "April";// 9 + case 5 -> "May";// 10 + case 6 -> "June";// 11 + case 7 -> "July";// 12 + case 8 -> "August";// 13 + case 9 -> "September";// 14 + case 10 -> "October";// 15 + case 11 -> "November";// 16 + case 12 -> "December";// 17 + default -> throw new IllegalStateException("Unexpected value: " + x);// 18 + }; System.out.println(month);// 20 }// 21 } class 'pkg/TestAssignmentSwitchExpression1' { method 'test (I)V' { - 0 5 - 1 5 - 40 7 - 41 7 - 42 8 - 45 10 - 46 10 - 47 11 - 4a 13 - 4b 13 - 4c 14 - 4f 16 - 50 16 - 51 17 - 54 19 - 55 19 - 56 20 - 59 22 - 5a 22 - 5b 23 - 5e 25 - 5f 25 - 60 26 - 63 28 - 64 28 - 65 29 - 68 31 - 69 31 - 6a 32 - 6d 34 - 6e 34 - 6f 35 - 72 37 - 73 37 - 74 38 - 77 40 - 78 40 - 79 41 - 80 43 - 81 43 - 82 43 - 83 43 - 84 43 - 85 43 - 89 43 - 8a 46 - 8b 47 - 8c 47 - 8d 47 - 8e 47 - 8f 47 - 90 47 - 91 47 - 92 48 + 0 4 + 1 4 + 40 5 + 41 5 + 45 6 + 46 6 + 4a 7 + 4b 7 + 4f 8 + 50 8 + 54 9 + 55 9 + 59 10 + 5a 10 + 5e 11 + 5f 11 + 63 12 + 64 12 + 68 13 + 69 13 + 6d 14 + 6e 14 + 72 15 + 73 15 + 77 16 + 78 16 + 80 17 + 81 17 + 82 17 + 83 17 + 84 17 + 85 17 + 89 17 + 8a 4 + 8b 19 + 8c 19 + 8d 19 + 8e 19 + 8f 19 + 90 19 + 91 19 + 92 20 } } Lines mapping: -5 <-> 6 -6 <-> 8 -7 <-> 11 -8 <-> 14 -9 <-> 17 -10 <-> 20 -11 <-> 23 -12 <-> 26 -13 <-> 29 -14 <-> 32 -15 <-> 35 -16 <-> 38 -17 <-> 41 -18 <-> 44 -20 <-> 48 -21 <-> 49 +5 <-> 5 +6 <-> 6 +7 <-> 7 +8 <-> 8 +9 <-> 9 +10 <-> 10 +11 <-> 11 +12 <-> 12 +13 <-> 13 +14 <-> 14 +15 <-> 15 +16 <-> 16 +17 <-> 17 +18 <-> 18 +20 <-> 20 +21 <-> 21 diff --git a/testData/results/pkg/TestAssignmentSwitchExpression2.dec b/testData/results/pkg/TestAssignmentSwitchExpression2.dec index dbc04e6bed..1533d822df 100644 --- a/testData/results/pkg/TestAssignmentSwitchExpression2.dec +++ b/testData/results/pkg/TestAssignmentSwitchExpression2.dec @@ -2,66 +2,46 @@ package pkg; public class TestAssignmentSwitchExpression2 { public void test(int x) { - String var10000; - switch(x) {// 5 - case 1: - case 3: - case 5: - case 7: - case 9: - case 11: - var10000 = "Odd";// 6 - break; - case 2: - case 4: - case 6: - case 8: - case 10: - case 12: - var10000 = "Even";// 7 - break; - default: - throw new IllegalStateException("Unexpected value: " + x);// 8 - } - - String a = var10000; + String a = switch(x) {// 5 + case 1, 3, 5, 7, 9, 11 -> "Odd";// 6 + case 2, 4, 6, 8, 10, 12 -> "Even";// 7 + default -> throw new IllegalStateException("Unexpected value: " + x);// 8 + }; System.out.println(a);// 10 }// 11 } class 'pkg/TestAssignmentSwitchExpression2' { method 'test (I)V' { - 0 5 - 1 5 - 40 12 - 41 12 - 42 13 - 45 20 - 46 20 - 47 21 - 4e 23 - 4f 23 - 50 23 - 51 23 - 52 23 - 53 23 - 57 23 - 58 26 - 59 27 - 5a 27 - 5b 27 - 5c 27 - 5d 27 - 5e 27 - 5f 27 - 60 28 + 0 4 + 1 4 + 40 5 + 41 5 + 45 6 + 46 6 + 4e 7 + 4f 7 + 50 7 + 51 7 + 52 7 + 53 7 + 57 7 + 58 4 + 59 9 + 5a 9 + 5b 9 + 5c 9 + 5d 9 + 5e 9 + 5f 9 + 60 10 } } Lines mapping: -5 <-> 6 -6 <-> 13 -7 <-> 21 -8 <-> 24 -10 <-> 28 -11 <-> 29 +5 <-> 5 +6 <-> 6 +7 <-> 7 +8 <-> 8 +10 <-> 10 +11 <-> 11 diff --git a/testData/results/pkg/TestAssignmentSwitchExpression3.dec b/testData/results/pkg/TestAssignmentSwitchExpression3.dec index ea2547eaf1..4783304e9d 100644 --- a/testData/results/pkg/TestAssignmentSwitchExpression3.dec +++ b/testData/results/pkg/TestAssignmentSwitchExpression3.dec @@ -4,94 +4,74 @@ import java.util.Random; public class TestAssignmentSwitchExpression3 { public void test(int x) { - Random var10000; - switch(x) {// 7 - case -5: - case -4: - case -3: - case -2: - case -1: - int seed = x >> 2;// 14 - var10000 = new Random((long)seed);// 15 - break; - case 0: - default: - throw new IllegalStateException("Unexpected value: " + x);// 17 - case 1: - case 2: - case 3: - case 4: - case 5: - long seed = System.currentTimeMillis() - (long)(x * 1000);// 9 - var10000 = new Random(seed);// 10 - break; - case 6: - case 7: - case 8: - case 9: - case 10: - var10000 = new Random(); - } - - Random random = var10000; + Random random = switch(x) {// 7 + case -5, -4, -3, -2, -1 -> { + int seed = x >> 2;// 14 + yield new Random((long)seed);// 15 + } + default -> throw new IllegalStateException("Unexpected value: " + x);// 17 + case 1, 2, 3, 4, 5 -> { + long seed = System.currentTimeMillis() - (long)(x * 1000);// 9 + yield new Random(seed);// 10 + } + case 6, 7, 8, 9, 10 -> new Random(); + }; System.out.println(random.nextInt());// 19 }// 20 } class 'pkg/TestAssignmentSwitchExpression3' { method 'test (I)V' { - 0 7 - 1 7 - 50 24 - 51 24 - 52 24 - 53 24 - 54 24 - 55 24 - 56 24 - 57 24 - 58 24 - 59 24 - 5a 24 - 5f 25 - 63 26 - 70 13 - 71 13 - 72 13 - 73 13 - 78 14 - 79 14 - 7d 15 - 84 18 - 85 18 - 86 18 - 87 18 - 88 18 - 89 18 - 8d 18 - 8e 35 - 8f 36 - 90 36 - 91 36 - 92 36 - 93 36 - 94 36 - 95 36 - 96 36 - 97 36 - 98 36 - 99 37 + 0 6 + 1 6 + 50 13 + 51 13 + 52 13 + 53 13 + 54 13 + 55 13 + 56 13 + 57 13 + 58 13 + 59 13 + 5a 13 + 5f 14 + 70 8 + 71 8 + 72 8 + 73 8 + 78 9 + 79 9 + 84 11 + 85 11 + 86 11 + 87 11 + 88 11 + 89 11 + 8d 11 + 8e 6 + 8f 18 + 90 18 + 91 18 + 92 18 + 93 18 + 94 18 + 95 18 + 96 18 + 97 18 + 98 18 + 99 19 } } Lines mapping: -7 <-> 8 -9 <-> 25 -10 <-> 26 -14 <-> 14 -15 <-> 15 -17 <-> 19 -19 <-> 37 -20 <-> 38 +7 <-> 7 +9 <-> 14 +10 <-> 15 +14 <-> 9 +15 <-> 10 +17 <-> 12 +19 <-> 19 +20 <-> 20 Not mapped: 12 diff --git a/testData/results/pkg/TestAssignmentSwitchExpression4.dec b/testData/results/pkg/TestAssignmentSwitchExpression4.dec index d0835fd43c..ac7bb454b3 100644 --- a/testData/results/pkg/TestAssignmentSwitchExpression4.dec +++ b/testData/results/pkg/TestAssignmentSwitchExpression4.dec @@ -3,25 +3,13 @@ package pkg; public class TestAssignmentSwitchExpression4 { public void test(String directionStr) { String var3 = directionStr.toLowerCase();// 5 - String var10000; - switch(var3) { - case "north": - case "south": - var10000 = "y";// 8 - break; - case "east": - case "west": - var10000 = "x";// 11 - break; - case "up": - case "down": - var10000 = "z";// 14 - break; - default: - throw new IllegalStateException("Unexpected value: " + directionStr);// 16 - } - String axis = var10000; + String axis = switch(var3) { + case "north", "south" -> "y";// 8 + case "east", "west" -> "x";// 11 + case "up", "down" -> "z";// 14 + default -> throw new IllegalStateException("Unexpected value: " + directionStr);// 16 + }; System.out.println(axis);// 18 }// 19 } @@ -36,50 +24,47 @@ class 'pkg/TestAssignmentSwitchExpression4' { 8 6 49 7 4a 7 - 58 8 - 59 8 - 67 11 - 68 11 - 76 12 - 77 12 - 85 15 - 86 15 - 94 16 - 95 16 + 58 7 + 59 7 + 67 8 + 68 8 + 76 8 + 77 8 + 85 9 + 86 9 + 94 9 + 95 9 a1 6 - c8 9 - c9 9 - ca 10 - cd 13 - ce 13 - cf 14 - d2 17 - d3 17 - d4 18 - db 20 - dc 20 - dd 20 - de 20 - df 20 - e0 20 - e4 20 - e5 23 - e6 24 - e7 24 - e8 24 - e9 24 - ea 24 - eb 24 - ec 24 - ed 25 + c8 7 + c9 7 + cd 8 + ce 8 + d2 9 + d3 9 + db 10 + dc 10 + dd 10 + de 10 + df 10 + e0 10 + e4 10 + e5 6 + e6 12 + e7 12 + e8 12 + e9 12 + ea 12 + eb 12 + ec 12 + ed 13 } } Lines mapping: 5 <-> 5 -8 <-> 10 -11 <-> 14 -14 <-> 18 -16 <-> 21 -18 <-> 25 -19 <-> 26 +8 <-> 8 +11 <-> 9 +14 <-> 10 +16 <-> 11 +18 <-> 13 +19 <-> 14 diff --git a/testData/results/pkg/TestAssignmentSwitchExpression5.dec b/testData/results/pkg/TestAssignmentSwitchExpression5.dec index 6f02255c6d..44803172be 100644 --- a/testData/results/pkg/TestAssignmentSwitchExpression5.dec +++ b/testData/results/pkg/TestAssignmentSwitchExpression5.dec @@ -5,25 +5,13 @@ public class TestAssignmentSwitchExpression5 { String axis; for(axis = directionStr; i > 0; --i) {// 5 6 20 String var4 = directionStr.toLowerCase();// 7 - String var10000; - switch(var4) { - case "north": - case "south": - var10000 = "y";// 10 - break; - case "east": - case "west": - var10000 = "x";// 13 - break; - case "up": - case "down": - var10000 = "z";// 16 - break; - default: - throw new IllegalStateException("Unexpected value: " + directionStr);// 18 - } - axis = var10000; + axis = switch(var4) { + case "north", "south" -> "y";// 10 + case "east", "west" -> "x";// 13 + case "up", "down" -> "z";// 16 + default -> throw new IllegalStateException("Unexpected value: " + directionStr);// 18 + }; } System.out.println(axis);// 22 @@ -46,45 +34,42 @@ class 'pkg/TestAssignmentSwitchExpression5' { 10 8 52 9 53 9 - 62 10 - 63 10 - 72 13 - 73 13 - 82 14 - 83 14 - 92 17 - 93 17 - a2 18 - a3 18 + 62 9 + 63 9 + 72 10 + 73 10 + 82 10 + 83 10 + 92 11 + 93 11 + a2 11 + a3 11 af 8 - d4 11 - d5 11 - d6 12 - d9 15 - da 15 - db 16 - de 19 - df 19 - e0 20 - e7 22 - e8 22 - e9 22 - ea 22 - eb 22 - ec 22 - f0 22 - f1 25 + d4 9 + d5 9 + d9 10 + da 10 + de 11 + df 11 + e7 12 + e8 12 + e9 12 + ea 12 + eb 12 + ec 12 + f0 12 + f1 8 f2 5 f3 5 f4 5 - f8 28 - f9 28 - fa 28 - fb 28 - fc 28 - fd 28 - fe 28 - ff 29 + f8 16 + f9 16 + fa 16 + fb 16 + fc 16 + fd 16 + fe 16 + ff 17 } } @@ -92,10 +77,10 @@ Lines mapping: 5 <-> 6 6 <-> 6 7 <-> 7 -10 <-> 12 -13 <-> 16 -16 <-> 20 -18 <-> 23 +10 <-> 10 +13 <-> 11 +16 <-> 12 +18 <-> 13 20 <-> 6 -22 <-> 29 -23 <-> 30 +22 <-> 17 +23 <-> 18 diff --git a/testData/results/pkg/TestAssignmentSwitchExpression7.dec b/testData/results/pkg/TestAssignmentSwitchExpression7.dec new file mode 100644 index 0000000000..cc2acd3079 --- /dev/null +++ b/testData/results/pkg/TestAssignmentSwitchExpression7.dec @@ -0,0 +1,41 @@ +package pkg; + +public class TestAssignmentSwitchExpression7 { + public void test(int x) { + String str = switch(x) {// 5 + case 1 -> "1";// 6 + case 2 -> "2";// 7 + default -> "3";// 8 + }; + System.out.println(str);// 10 + }// 11 +} + +class 'pkg/TestAssignmentSwitchExpression7' { + method 'test (I)V' { + 0 4 + 1 4 + 1c 5 + 1d 5 + 21 6 + 22 6 + 26 7 + 28 4 + 29 9 + 2a 9 + 2b 9 + 2c 9 + 2d 9 + 2e 9 + 2f 9 + 30 10 + } +} + +Lines mapping: +5 <-> 5 +6 <-> 6 +7 <-> 7 +8 <-> 8 +10 <-> 10 +11 <-> 11 diff --git a/testData/results/pkg/TestConstructorSwitchExpression1.dec b/testData/results/pkg/TestConstructorSwitchExpression1.dec index dfe3e09786..c72bb056cb 100644 --- a/testData/results/pkg/TestConstructorSwitchExpression1.dec +++ b/testData/results/pkg/TestConstructorSwitchExpression1.dec @@ -2,60 +2,50 @@ package pkg; public class TestConstructorSwitchExpression1 { public TestConstructorSwitchExpression1(int i) { - String var10001; - switch(i) { - case 1: - var10001 = "1";// 6 - break; - case 2: - var10001 = "3";// 7 - break; - case 3: - default: - var10001 = "0";// 9 - break; - case 4: - var10001 = "5";// 8 - } - - this(var10001);// 5 + this(switch(i) {// 5 + case 1 -> "1";// 6 + case 2 -> "3";// 7 + default -> "0";// 9 + case 4 -> "5";// 8 + }); }// 11 public TestConstructorSwitchExpression1(String s) { + super();// 13 }// 15 } class 'pkg/TestConstructorSwitchExpression1' { method ' (I)V' { - 1 5 - 2 5 - 20 7 - 21 7 - 22 8 - 25 10 - 26 10 - 27 11 - 2a 17 - 2b 17 - 2f 14 - 31 20 - 32 20 - 33 20 - 34 21 + 1 4 + 2 4 + 20 5 + 21 5 + 25 6 + 26 6 + 2a 8 + 2b 8 + 2f 7 + 31 4 + 32 4 + 33 4 + 34 10 } method ' (Ljava/lang/String;)V' { - 4 24 + 1 13 + 2 13 + 3 13 + 4 14 } } Lines mapping: -5 <-> 21 -6 <-> 8 -7 <-> 11 -8 <-> 18 -9 <-> 15 -11 <-> 22 -15 <-> 25 -Not mapped: -13 +5 <-> 5 +6 <-> 6 +7 <-> 7 +8 <-> 9 +9 <-> 8 +11 <-> 11 +13 <-> 14 +15 <-> 15 diff --git a/testData/results/pkg/TestInlineSwitchExpression1.dec b/testData/results/pkg/TestInlineSwitchExpression1.dec index fd19646033..ef6b9f78a8 100644 --- a/testData/results/pkg/TestInlineSwitchExpression1.dec +++ b/testData/results/pkg/TestInlineSwitchExpression1.dec @@ -6,31 +6,16 @@ import java.io.PrintStream; public class TestInlineSwitchExpression1 { public void test(Direction direction) { PrintStream var10000 = System.out;// 7 - Direction var10001; - switch(direction) { - case NORTH: - var10001 = Direction.SOUTH;// 9 - break; - case SOUTH: - var10001 = Direction.NORTH;// 11 - break; - case EAST: - var10001 = Direction.WEST;// 13 - break; - case WEST: - var10001 = Direction.EAST;// 15 - break; - case UP: - var10001 = Direction.DOWN;// 17 - break; - case DOWN: - var10001 = Direction.UP;// 19 - break; - default: - throw new IncompatibleClassChangeError(); - } - var10000.println(var10001); + var10000.println(switch(direction) { + case NORTH -> Direction.SOUTH;// 9 + case SOUTH -> Direction.NORTH;// 11 + case EAST -> Direction.WEST;// 13 + case WEST -> Direction.EAST;// 15 + case UP -> Direction.DOWN;// 17 + case DOWN -> Direction.UP;// 19 + default -> throw new IncompatibleClassChangeError(); + }); }// 21 } @@ -41,44 +26,38 @@ class 'pkg/TestInlineSwitchExpression1' { 2 7 6 9 b 9 - 30 11 - 31 11 - 32 11 - 33 12 - 36 14 - 37 14 - 38 14 - 39 15 - 3c 17 - 3d 17 - 3e 17 - 3f 18 - 42 20 - 43 20 - 44 20 - 45 21 - 48 23 - 49 23 - 4a 23 - 4b 24 - 4e 26 - 4f 26 - 50 26 - 51 27 - 5b 29 - 5c 32 - 5d 32 - 5e 32 - 5f 33 + 30 10 + 31 10 + 32 10 + 36 11 + 37 11 + 38 11 + 3c 12 + 3d 12 + 3e 12 + 42 13 + 43 13 + 44 13 + 48 14 + 49 14 + 4a 14 + 4e 15 + 4f 15 + 50 15 + 5b 16 + 5c 9 + 5d 9 + 5e 9 + 5f 18 } } Lines mapping: 7 <-> 8 -9 <-> 12 -11 <-> 15 -13 <-> 18 -15 <-> 21 -17 <-> 24 -19 <-> 27 -21 <-> 34 +9 <-> 11 +11 <-> 12 +13 <-> 13 +15 <-> 14 +17 <-> 15 +19 <-> 16 +21 <-> 19 diff --git a/testData/results/pkg/TestInlineSwitchExpression3.dec b/testData/results/pkg/TestInlineSwitchExpression3.dec index c7faf1f80f..2fabd1260a 100644 --- a/testData/results/pkg/TestInlineSwitchExpression3.dec +++ b/testData/results/pkg/TestInlineSwitchExpression3.dec @@ -5,25 +5,14 @@ import java.io.PrintStream; public class TestInlineSwitchExpression3 { public void test(Direction direction) { - PrintStream var10000 = System.out;// 7 - byte var10001; - switch(direction) { - case NORTH: - case EAST: - case UP: - var10001 = -1;// 11 - break; - case SOUTH: - case WEST: - case DOWN: - var10001 = 1;// 15 - break; - default: - throw new IncompatibleClassChangeError(); - } + PrintStream var10000 = System.out;// 9 - var10000.println(var10001); - }// 17 + var10000.println(switch(direction) { + case NORTH, EAST, UP -> -1;// 13 + case SOUTH, WEST, DOWN -> 1;// 17 + default -> throw new IncompatibleClassChangeError(); + }); + }// 19 } class 'pkg/TestInlineSwitchExpression3' { @@ -33,20 +22,18 @@ class 'pkg/TestInlineSwitchExpression3' { 2 7 6 9 b 9 - 30 13 - 31 14 - 34 18 - 35 19 - 3f 21 - 40 24 - 41 24 - 42 24 - 43 25 + 30 10 + 34 11 + 3f 12 + 40 9 + 41 9 + 42 9 + 43 14 } } Lines mapping: -7 <-> 8 -11 <-> 14 -15 <-> 19 -17 <-> 26 +9 <-> 8 +13 <-> 11 +17 <-> 12 +19 <-> 15 diff --git a/testData/results/pkg/TestReturnSwitchExpression1.dec b/testData/results/pkg/TestReturnSwitchExpression1.dec index fe78f73bb1..84d1974ca9 100644 --- a/testData/results/pkg/TestReturnSwitchExpression1.dec +++ b/testData/results/pkg/TestReturnSwitchExpression1.dec @@ -2,39 +2,29 @@ package pkg; public class TestReturnSwitchExpression1 { public String test(int i) { - String var10000; - switch(i) { - case 1: - var10000 = "1";// 6 - break; - case 2: - var10000 = "2";// 7 - break; - default: - var10000 = "Unknown";// 8 - } - - return var10000;// 5 + return switch(i) {// 5 + case 1 -> "1";// 6 + case 2 -> "2";// 7 + default -> "Unknown";// 8 + }; } } class 'pkg/TestReturnSwitchExpression1' { method 'test (I)Ljava/lang/String;' { - 0 5 - 1 5 - 1c 7 - 1d 7 - 1e 8 - 21 10 - 22 10 - 23 11 - 26 13 - 28 16 + 0 4 + 1 4 + 1c 5 + 1d 5 + 21 6 + 22 6 + 26 7 + 28 4 } } Lines mapping: -5 <-> 17 -6 <-> 8 -7 <-> 11 -8 <-> 14 +5 <-> 5 +6 <-> 6 +7 <-> 7 +8 <-> 8 diff --git a/testData/results/pkg/TestReturnSwitchExpression2.dec b/testData/results/pkg/TestReturnSwitchExpression2.dec index 9348713dde..33130248ac 100644 --- a/testData/results/pkg/TestReturnSwitchExpression2.dec +++ b/testData/results/pkg/TestReturnSwitchExpression2.dec @@ -14,19 +14,11 @@ public class TestReturnSwitchExpression2 { var10000 = 3;// 8 } - String var2; - switch(var10000) { - case 1: - var2 = "1";// 10 - break; - case 2: - var2 = "2";// 11 - break; - default: - var2 = "Unknown";// 12 - } - - return var2;// 5 + return switch(var10000) {// 5 + case 1 -> "1";// 10 + case 2 -> "2";// 11 + default -> "Unknown";// 12 + }; } } @@ -39,23 +31,21 @@ class 'pkg/TestReturnSwitchExpression2' { 20 10 21 11 24 13 - 25 17 - 40 19 - 41 19 - 42 20 - 45 22 - 46 22 - 47 23 - 4a 25 - 4c 28 + 25 16 + 40 17 + 41 17 + 45 18 + 46 18 + 4a 19 + 4c 16 } } Lines mapping: -5 <-> 29 +5 <-> 17 6 <-> 8 7 <-> 11 8 <-> 14 -10 <-> 20 -11 <-> 23 -12 <-> 26 +10 <-> 18 +11 <-> 19 +12 <-> 20 diff --git a/testData/results/pkg/TestReturnSwitchExpression3.dec b/testData/results/pkg/TestReturnSwitchExpression3.dec index a90ec70022..e1193d8cf9 100644 --- a/testData/results/pkg/TestReturnSwitchExpression3.dec +++ b/testData/results/pkg/TestReturnSwitchExpression3.dec @@ -3,19 +3,12 @@ package pkg; public class TestReturnSwitchExpression3 { public String test(int i) { System.out.println(2);// 5 - String var10000; - switch(i) { - case 1: - var10000 = "1";// 8 - break; - case 2: - var10000 = "2";// 9 - break; - default: - var10000 = "Unknown";// 10 - } - return var10000;// 7 + return switch(i) {// 7 + case 1 -> "1";// 8 + case 2 -> "2";// 9 + default -> "Unknown";// 10 + }; } } @@ -30,20 +23,18 @@ class 'pkg/TestReturnSwitchExpression3' { 6 4 7 6 8 6 - 24 8 - 25 8 - 26 9 - 29 11 - 2a 11 - 2b 12 - 2e 14 - 30 17 + 24 7 + 25 7 + 29 8 + 2a 8 + 2e 9 + 30 6 } } Lines mapping: 5 <-> 5 -7 <-> 18 -8 <-> 9 -9 <-> 12 -10 <-> 15 +7 <-> 7 +8 <-> 8 +9 <-> 9 +10 <-> 10 diff --git a/testData/results/pkg/TestSwitchPatternMatchingConstructor2.dec b/testData/results/pkg/TestSwitchPatternMatchingConstructor2.dec index e5203a40f1..a12a5e6f39 100644 --- a/testData/results/pkg/TestSwitchPatternMatchingConstructor2.dec +++ b/testData/results/pkg/TestSwitchPatternMatchingConstructor2.dec @@ -10,16 +10,11 @@ public class TestSwitchPatternMatchingConstructor2 { private TestSwitchPatternMatchingConstructor2(Object s) { byte var3 = 0; - String var10001; - switch(SwitchBootstraps.typeSwitch<"typeSwitch">(s, var3)) { - case -1: - var10001 = "null";// 10 - break; - default: - var10001 = "Non-triangle";// 11 - } - this(var10001);// 9 + this(switch(SwitchBootstraps.typeSwitch<"typeSwitch">(s, var3)) {// 9 + case -1 -> "null";// 10 + default -> "Non-triangle";// 11 + }); }// 13 private TestSwitchPatternMatchingConstructor2(Object s, boolean unused) { @@ -55,50 +50,49 @@ class 'pkg/TestSwitchPatternMatchingConstructor2' { a 13 b 13 c 13 - 20 15 - 21 15 - 22 16 - 25 18 - 27 21 - 28 21 - 29 21 - 2a 22 + 20 14 + 21 14 + 25 15 + 27 13 + 28 13 + 29 13 + 2a 17 } method ' (Ljava/lang/Object;Z)V' { - 1 25 - 3 25 - 4 25 - 5 25 - 8 26 - 9 26 - a 26 - c 27 - d 27 - e 27 - f 27 - 10 27 - 11 27 - 12 27 - 13 27 - 1c 29 - 1d 29 - 1e 29 - 1f 29 - 20 29 - 21 31 + 1 20 + 3 20 + 4 20 + 5 20 + 8 21 + 9 21 + a 21 + c 22 + d 22 + e 22 + f 22 + 10 22 + 11 22 + 12 22 + 13 22 + 1c 24 + 1d 24 + 1e 24 + 1f 24 + 20 24 + 21 26 } } Lines mapping: 5 <-> 8 6 <-> 9 -9 <-> 22 -10 <-> 16 -11 <-> 19 -13 <-> 23 -16 <-> 30 -17 <-> 30 -19 <-> 32 +9 <-> 14 +10 <-> 15 +11 <-> 16 +13 <-> 18 +16 <-> 25 +17 <-> 25 +19 <-> 27 Not mapped: 4 diff --git a/testData/results/pkg/TestSwitchPatternMatchingReturn1.dec b/testData/results/pkg/TestSwitchPatternMatchingReturn1.dec index a46e4de9a8..e7879d20d9 100644 --- a/testData/results/pkg/TestSwitchPatternMatchingReturn1.dec +++ b/testData/results/pkg/TestSwitchPatternMatchingReturn1.dec @@ -7,21 +7,18 @@ public class TestSwitchPatternMatchingReturn1 { public int test(Object o) { Objects.requireNonNull(o); byte var3 = 0; - int var10000; - switch(SwitchBootstraps.typeSwitch<"typeSwitch",Integer,String>(o, var3)) { - case 0: - Integer i = (Integer)o;// 6 - var10000 = i; - break; - case 1: - String s = (String)o; - var10000 = s.length();// 7 - break; - default: - var10000 = 0;// 8 - } - return var10000;// 5 + return switch(SwitchBootstraps.typeSwitch<"typeSwitch",Integer,String>(o, var3)) {// 5 + case 0 -> { + Integer i = (Integer)o;// 6 + yield i; + } + case 1 -> { + String s = (String)o; + yield s.length();// 7 + } + default -> 0;// 8 + }; } } @@ -50,7 +47,6 @@ class 'pkg/TestSwitchPatternMatchingReturn1' { 34 13 35 13 36 13 - 37 14 3b 16 3c 16 3d 16 @@ -61,14 +57,13 @@ class 'pkg/TestSwitchPatternMatchingReturn1' { 42 17 43 17 44 17 - 45 18 - 48 20 - 49 23 + 48 19 + 49 10 } } Lines mapping: -5 <-> 24 +5 <-> 11 6 <-> 13 7 <-> 18 -8 <-> 21 +8 <-> 20 diff --git a/testData/src/java16/pkg/TestAssignmentSwitchExpression7.java b/testData/src/java16/pkg/TestAssignmentSwitchExpression7.java new file mode 100644 index 0000000000..7f576ab79c --- /dev/null +++ b/testData/src/java16/pkg/TestAssignmentSwitchExpression7.java @@ -0,0 +1,12 @@ +package pkg; + +public class TestAssignmentSwitchExpression7 { + public void test(int x) { + String str = switch (x) { + case 1 -> "1"; + case 2 -> "2"; + default -> "3"; + }; + System.out.println(str); + } +} diff --git a/testData/src/java16/pkg/TestInlineSwitchExpression3.java b/testData/src/java16/pkg/TestInlineSwitchExpression3.java index 94e59439a9..a694843499 100644 --- a/testData/src/java16/pkg/TestInlineSwitchExpression3.java +++ b/testData/src/java16/pkg/TestInlineSwitchExpression3.java @@ -2,6 +2,8 @@ import ext.Direction; +import java.io.PrintStream; + public class TestInlineSwitchExpression3 { public void test(Direction direction) { System.out.println(switch (direction) { From 702accac6d44c130a3d14fce9c28b12e20d78e62 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 16 Nov 2021 17:03:28 -0500 Subject: [PATCH 18/85] Add text block test --- .../java/decompiler/util/DotExporter.java | 2 +- .../java/decompiler/SingleClassesTest.java | 1 + testData/results/pkg/TestTextBlocks.dec | 55 +++++++++++++++++++ testData/src/java16/pkg/TestTextBlocks.java | 35 ++++++++++++ 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 testData/results/pkg/TestTextBlocks.dec create mode 100644 testData/src/java16/pkg/TestTextBlocks.java diff --git a/src/org/jetbrains/java/decompiler/util/DotExporter.java b/src/org/jetbrains/java/decompiler/util/DotExporter.java index 7dc89d214d..01715b163a 100644 --- a/src/org/jetbrains/java/decompiler/util/DotExporter.java +++ b/src/org/jetbrains/java/decompiler/util/DotExporter.java @@ -270,7 +270,7 @@ private static void recursivelyGraphStatement(StringBuffer buffer, Statement sta private static String toJava(Statement statement) { try { - String java = statement.toJava().toString().replace("\"", "\\\""); + String java = statement.toJava().convertToStringAndAllowDataDiscard().replace("\"", "\\\""); if (statement instanceof BasicBlockStatement) { if (statement.getExprents() == null || statement.getExprents().isEmpty()) { java = "<" + (statement.getExprents() == null ? "null" : "empty") + " basic block>\n" + java; diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 5933e205f8..f0a0c2302c 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -383,6 +383,7 @@ private void registerDefault() { register(JAVA_8, "TestPPMMOnObjectField"); register(JAVA_8, "TestPPMMOnStaticField"); register(JAVA_17, "TestImplicitlySealedEnum"); + register(JAVA_16, "TestTextBlocks"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestTextBlocks.dec b/testData/results/pkg/TestTextBlocks.dec new file mode 100644 index 0000000000..65f2c0b315 --- /dev/null +++ b/testData/results/pkg/TestTextBlocks.dec @@ -0,0 +1,55 @@ +package pkg; + +public class TestTextBlocks { + private final String text = "Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n"; + + public void testLocal() { + String local = "Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n";// 13 + }// 20 + + public void testCall() { + this.useString("Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n");// 23 + }// 30 + + private void useString(String s) { + System.out.println(s);// 33 + }// 34 +} + +class 'pkg/TestTextBlocks' { + method 'testLocal ()V' { + 0 6 + 1 6 + 2 6 + 3 7 + } + + method 'testCall ()V' { + 0 10 + 1 10 + 2 10 + 3 10 + 4 10 + 5 10 + 6 11 + } + + method 'useString (Ljava/lang/String;)V' { + 0 14 + 1 14 + 2 14 + 3 14 + 4 14 + 5 14 + 6 14 + 7 15 + } +} + +Lines mapping: +13 <-> 7 +20 <-> 8 +23 <-> 11 +30 <-> 12 +33 <-> 15 +34 <-> 16 diff --git a/testData/src/java16/pkg/TestTextBlocks.java b/testData/src/java16/pkg/TestTextBlocks.java new file mode 100644 index 0000000000..44a0f4a534 --- /dev/null +++ b/testData/src/java16/pkg/TestTextBlocks.java @@ -0,0 +1,35 @@ +package pkg; + +public class TestTextBlocks { + private final String text = """ + Hello! + This is a text block! + It's multiple lines long. + I can use "quotes" in it. + It's rather cool. + """; + + public void testLocal() { + String local = """ + Hello! + This is a text block! + It's multiple lines long. + I can use "quotes" in it. + It's rather cool. + """; + } + + public void testCall() { + useString(""" + Hello! + This is a text block! + It's multiple lines long. + I can use "quotes" in it. + It's rather cool. + """); + } + + private void useString(String s) { + System.out.println(s); + } +} From dba9bfb59b56c087c16cdf38653de9ec00821172 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 16 Nov 2021 22:10:02 +0000 Subject: [PATCH 19/85] Fix tests --- .../modules/decompiler/exps/NewExprent.java | 8 ++++---- .../jetbrains/java/decompiler/util/DotExporter.java | 2 +- .../jetbrains/java/decompiler/util/TextBuffer.java | 4 +++- .../jetbrains/java/decompiler/SingleClassesTest.java | 1 + testData/src/java8/pkg/TestQualifiedNew.java | 12 ++++++++++++ 5 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 testData/src/java8/pkg/TestQualifiedNew.java 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 4a6e4a6424..2bc3770105 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -324,7 +324,7 @@ public TextBuffer toJava(int indent) { // IDEA-204310 - avoid backtracking later on for lambdas (causes spurious imports) if (!enumConst && (!lambda || DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS))) { - String enclosing = null; + TextBuffer enclosing = null; if (!lambda && constructor != null) { enclosing = getQualifiedNewInstance(child.anonymousClassType.value, constructor.getLstParameters(), indent); @@ -408,7 +408,7 @@ else if (directArrayInit) { } else if (newType.arrayDim == 0) { if (!enumConst) { - String enclosing = null; + TextBuffer enclosing = null; if (constructor != null) { enclosing = getQualifiedNewInstance(newType.value, constructor.getLstParameters(), indent); @@ -502,7 +502,7 @@ public static boolean probablySyntheticParameter(String className) { return node != null && node.type == ClassNode.CLASS_ANONYMOUS; } - private static String getQualifiedNewInstance(String classname, List lstParams, int indent) { + private static TextBuffer getQualifiedNewInstance(String classname, List lstParams, int indent) { ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); if (node != null && node.type != ClassNode.CLASS_ROOT && node.type != ClassNode.CLASS_LOCAL @@ -527,7 +527,7 @@ private static String getQualifiedNewInstance(String classname, List ls } if (isQualifiedNew) { - return enclosing.toJava(indent).toString(); + return enclosing.toJava(indent); } } } diff --git a/src/org/jetbrains/java/decompiler/util/DotExporter.java b/src/org/jetbrains/java/decompiler/util/DotExporter.java index 7dc89d214d..01715b163a 100644 --- a/src/org/jetbrains/java/decompiler/util/DotExporter.java +++ b/src/org/jetbrains/java/decompiler/util/DotExporter.java @@ -270,7 +270,7 @@ private static void recursivelyGraphStatement(StringBuffer buffer, Statement sta private static String toJava(Statement statement) { try { - String java = statement.toJava().toString().replace("\"", "\\\""); + String java = statement.toJava().convertToStringAndAllowDataDiscard().replace("\"", "\\\""); if (statement instanceof BasicBlockStatement) { if (statement.getExprents() == null || statement.getExprents().isEmpty()) { java = "<" + (statement.getExprents() == null ? "null" : "empty") + " basic block>\n" + java; diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index 7f25310854..c199bc2125 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -152,7 +152,9 @@ public boolean contentEquals(String string) { } public String convertToStringAndAllowDataDiscard() { - myDebugTrace.myPreventDeletion = false; + if (myDebugTrace != null) { + myDebugTrace.myPreventDeletion = false; + } String original = myStringBuilder.toString(); if (myLineToOffsetMapping == null || myLineToOffsetMapping.isEmpty()) { if (myLineMapping != null) { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 26be6cfc44..53543afd43 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -161,6 +161,7 @@ private void registerDefault() { register(JAVA_8, "TestEmptyBlocks"); register(JAVA_8, "TestInvertedFloatComparison"); register(JAVA_8, "TestPrivateEmptyConstructor"); + register(JAVA_8, "TestQualifiedNew"); // TODO: the local variable name there is wildly mangled register(KOTLIN, "TestSynchronizedUnprotected"); register(JAVA_8, "TestInterfaceSuper"); diff --git a/testData/src/java8/pkg/TestQualifiedNew.java b/testData/src/java8/pkg/TestQualifiedNew.java new file mode 100644 index 0000000000..02458634e9 --- /dev/null +++ b/testData/src/java8/pkg/TestQualifiedNew.java @@ -0,0 +1,12 @@ +package pkg; + +public class TestQualifiedNew { + public void foo() { + TestQualifiedNew instance = new TestQualifiedNew(); + instance.new Inner(); + } + + public class Inner { + + } +} From cfc5cb5c096709cc52efe042fdb25bc033c7a04c Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 16 Nov 2021 17:12:19 -0500 Subject: [PATCH 20/85] Add dec --- testData/results/pkg/TestQualifiedNew.dec | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 testData/results/pkg/TestQualifiedNew.dec diff --git a/testData/results/pkg/TestQualifiedNew.dec b/testData/results/pkg/TestQualifiedNew.dec new file mode 100644 index 0000000000..0cf3466a36 --- /dev/null +++ b/testData/results/pkg/TestQualifiedNew.dec @@ -0,0 +1,24 @@ +package pkg; + +public class TestQualifiedNew { + public void foo() { + TestQualifiedNew instance = new TestQualifiedNew();// 5 + instance.new Inner();// 6 + }// 7 + + public class Inner { + } +} + +class 'pkg/TestQualifiedNew' { + method 'foo ()V' { + 7 4 + c 5 + 16 6 + } +} + +Lines mapping: +5 <-> 5 +6 <-> 6 +7 <-> 7 From cf26fb20c3575dad0d6242bf0e8d305e344297a7 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 16 Nov 2021 23:05:01 +0000 Subject: [PATCH 21/85] Add comments and docs --- .../java/decompiler/util/TextBuffer.java | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index 25a3d49e4d..deccdee442 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -73,6 +73,20 @@ public TextBuffer appendIndent(int length) { return this; } + /** + * Pushes a newline group. + *

+ * {@link #appendPossibleNewline} normally works like append, adding its string argument to the buffer. However, if + * the line is running out of space, this text may later be replaced with a newline (plus indents). + * Possible newlines are grouped into newline groups. In a newline group, either none of the replacements are replaced + * with newlines, or all of them are (never only some of them). Possible newlines should not be added outside a group. + * The API works as if there were a stack of newline groups. This method pushes to the stack and + * {@link #popNewlineGroup()} pops from it. After the full source code has been generated, {@link #reformat()} is + * called to actually substitute the text. + * + * @param baseIndent The indent that has already been explicitly applied + * @param extraIndent The indent to be added if this group is applied + */ public TextBuffer pushNewlineGroup(int baseIndent, int extraIndent) { NewlineGroup group = new NewlineGroup(myCurrentGroup, myStringBuilder.length(), baseIndent, extraIndent); myCurrentGroup.myChildren.add(group); @@ -80,14 +94,24 @@ public TextBuffer pushNewlineGroup(int baseIndent, int extraIndent) { return this; } + /** + * If the current group is applied, add a newline here. + */ public TextBuffer appendPossibleNewline() { return appendPossibleNewline(""); } + /** + * If the current group is applied, add a newline here. Otherwise, add the argument. + */ public TextBuffer appendPossibleNewline(String alternative) { return appendPossibleNewline(alternative, false); } + /** + * If the current group is applied, add a newline here. Otherwise, add the argument. + * If {@code dedent} is true, the extra indent from this group is unapplied from this point on. + */ public TextBuffer appendPossibleNewline(String alternative, boolean dedent) { myCurrentGroup.myReplacements.add(new NewlineGroup.Replacement(myStringBuilder.length(), alternative.length(), dedent)); return append(alternative); @@ -181,13 +205,25 @@ public Map, BytecodeMappingTracer> getTracers() { return tracers; } + /** + * Recursive reformatting of groups. + * If the group's content would take you over the specified preferred line length, then the group is applied. + * + * - This algorithm usually ensures that if a group is applied, then all the group's parents in the tree are also + * applied. This tends to produce a nice structured output with well-placed potential newlines. + * - The formatter keeps track of the offset as a result of the reformat at each character in the text buffer, and + * applies them to the bytecode offsets afterwards, so that the line number mappings don't get messed up. + */ private void reformatGroup(NewlineGroup group, List offsetMapping, int extraIndent) { int offset = offsetMapping.get(group.myStart); int actualStart = group.myStart + offset; + // Find the last newline before the start of this group, so we know how long the line already is int lastNewline = myStringBuilder.lastIndexOf(myLineSeparator, actualStart); int nextNewline = myStringBuilder.indexOf(myLineSeparator, actualStart); - int firstGroupEnd = nextNewline == -1 ? actualStart + group.myLength : Math.min(nextNewline, actualStart + group.myLength); - int groupEndWithoutNewlines = lastNewline == -1 ? firstGroupEnd : firstGroupEnd - lastNewline; + // Find the end of the first line of this group, if the group were to not be reformatted + int firstPartEnd = nextNewline == -1 ? actualStart + group.myLength : Math.min(nextNewline, actualStart + group.myLength); + // Go through all lines in the group, and find the longest one (without reformatting) + int groupEndWithoutNewlines = lastNewline == -1 ? firstPartEnd : firstPartEnd - lastNewline; while (nextNewline != -1 && nextNewline <= actualStart + group.myLength) { int lineStart = nextNewline; int lineEnd = nextNewline = myStringBuilder.indexOf(myLineSeparator, nextNewline + 1); @@ -199,13 +235,17 @@ private void reformatGroup(NewlineGroup group, List offsetMapping, int groupEndWithoutNewlines = lineLength; } } + // If the longest line is longer than the preferred line length, then reformat the group boolean addNewLines = groupEndWithoutNewlines > myPreferredLineLength; int originalExtraIndent = extraIndent; + // If we're reformatting this group, and not only its children, then apply extra indentation if (addNewLines && !group.myReplacements.isEmpty()) { extraIndent += group.myExtraIndent; } + // Iterate over the children and replacements in one go rather than separately, because offsets need to be applied + // from left to right int childrenIndex = 0; int replacementIndex = 0; for (int pos = group.myStart; pos <= group.myStart + group.myLength; pos++) { @@ -222,6 +262,8 @@ private void reformatGroup(NewlineGroup group, List offsetMapping, int offset += myIndent.length() * extraIndent; } + // do multiple passes in an inner loop, as there could be arbitrarily many with the same offset + // or replacements with offsets equal to the end position of a child group boolean anotherPass = true; while (anotherPass) { anotherPass = false; @@ -240,6 +282,8 @@ private void reformatGroup(NewlineGroup group, List offsetMapping, int replacementIndex++; anotherPass = true; } + // offset may have changed, update the offset mapping here because the child groups rely on the value being + // correct in the list offsetMapping.set(offsetMapping.size() - 1, offset); // recursively iterate through child groups @@ -254,6 +298,9 @@ private void reformatGroup(NewlineGroup group, List offsetMapping, int } } } + + // update the offset value here because it might have changed when adding indents after existing newlines + // the parent relies on the value being correct in the list offsetMapping.set(offsetMapping.size() - 1, offset); } From c6eb62aa35712445a27244c0b707276df8495e61 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 16 Nov 2021 20:43:57 -0500 Subject: [PATCH 22/85] Add some tests for obscure code --- .../java/decompiler/SingleClassesTest.java | 4 + testData/classes/custom/Java14Test.class | Bin 0 -> 1085 bytes testData/classes/custom/JsHurt.class | Bin 0 -> 354 bytes testData/classes/custom/TestJsr.class | Bin 0 -> 507 bytes testData/classes/custom/TestJsr2.class | Bin 0 -> 759 bytes testData/results/Java14Test.dec | 60 ++++++++ testData/results/JsHurt.dec | 36 +++++ testData/results/TestJsr.dec | 34 +++++ testData/results/TestJsr2.dec | 139 ++++++++++++++++++ 9 files changed, 273 insertions(+) create mode 100644 testData/classes/custom/Java14Test.class create mode 100644 testData/classes/custom/JsHurt.class create mode 100644 testData/classes/custom/TestJsr.class create mode 100644 testData/classes/custom/TestJsr2.class create mode 100644 testData/results/Java14Test.dec create mode 100644 testData/results/JsHurt.dec create mode 100644 testData/results/TestJsr.dec create mode 100644 testData/results/TestJsr2.dec diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 51106e4504..049ff8f973 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -384,6 +384,10 @@ private void registerDefault() { register(JAVA_8, "TestPPMMOnStaticField"); register(JAVA_17, "TestImplicitlySealedEnum"); register(JAVA_16, "TestTextBlocks"); + registerRaw(CUSTOM, "Java14Test"); // Used from CFR + registerRaw(CUSTOM, "JsHurt"); // Used from CFR + registerRaw(CUSTOM, "TestJsr"); + registerRaw(CUSTOM, "TestJsr2"); } private void registerEntireClassPath() { diff --git a/testData/classes/custom/Java14Test.class b/testData/classes/custom/Java14Test.class new file mode 100644 index 0000000000000000000000000000000000000000..8cf0855eb92660a4dff5b2a53f58d0361bfe37ab GIT binary patch literal 1085 zcmZ`%TTc^F5dIFm?4@f91uJ;Lf<@YbTUzmwpeClsgK6qR8xtP4%eE{jyJmapNxZMoq#)2E}#;+;B{*#xU0~yB@a&yz<(3Z&WwiHwlTAv)gZ*kjX$OTjZDhN=a#XZ~UF(jYaj?G^%#EPZ2 z4Dq_VXE9_NwqrGihaJmn8=XEyVjaU{SS?Ej-R8+$fmNneMZ4EQXMwqd+YRC!pw5XyD2deQ zvx0st{Uc<_lSNB(yH38ik;L;`f;?)S>;mPU`z&Coe1c^87}9TKvhoPZ?pH{kk)+57 z>Nljm5SZa6Srt=cV~A5(MGPl=Do=4n8Tl02?g_3PoimbtTq1i1iy^uiq8F~JIZ00u z@hU0H9AEL+42bNsBwxI$&IglN8%T~4r(mn Tzb={$q^H73GTfus6bk#$77CQEiA*!v|m+G?R- zVP)mF_zmivq!OIsUha9^bLaE>?Hwj|vB|+1_^gnbN;3v)C^M<{8M>!Qd=rN<56?9h zsY1llfeQmRgPE6#!K)N$oK3>Bt3-?mYX4(mX!ys$h+Mv|PL!9$SRBe!aP%B7tWoUA z{HQDxN6W!7nhZVvvOb_%Pw6t741$pj7wa5LwDTap77VT0xR?AnC%T<0F?H#OjtdJ7 zl22oqVH<7A)6bwzEY%K8E7UdK+~ljdP#qk=UZz$XK+Wey+UTzuSV`7>7gFYx+a R=N{JM&sS|@SRkQ+?k_LzNA>^! literal 0 HcmV?d00001 diff --git a/testData/classes/custom/TestJsr.class b/testData/classes/custom/TestJsr.class new file mode 100644 index 0000000000000000000000000000000000000000..6e27ecb5e8ddaa2b0b541a0f7b3fb1b9acb253a7 GIT binary patch literal 507 zcmZuu$xZ@65PdxZ%rFjuB1A>pPN-2n0ON(|!3=5w;o_+oJEX}hWEP`;ghxDR;z93z zl(8C#OJX0Yx?Weks#pE~@$w2ChuAf-Vq(p}x`7P?bpx9gvas^VVZlNMwv7@BHnvf< zv4cehy|LG4s5G1rzvWGj2g7DJiDWQrDZJXa{{JC&ECZRGFl5@{jbJFW!yrz0ko38i zQf!^xxni71LaE1j95ECf8HkJ2ABd>O2OcF=zPM%ByrPZ?^%dN2F)TWv%e_92q{<@# zs~e_~E6${<%Jf8>Fc`|si0%39NJ(HQ&y@TnWhnjVyBv&!OANoD?tPpHpSXQ40~$C? zRfn;f$_r>wI&D!M4S8!yI#(wI}2!u%^xg*@L%^f*3&$8YKfJY_cSo pY;{Ja3NwW3DAVuM$kRk9%&F_-Rb6)f8OHRxG&cj)(<)&aYM-iWXwLuu literal 0 HcmV?d00001 diff --git a/testData/classes/custom/TestJsr2.class b/testData/classes/custom/TestJsr2.class new file mode 100644 index 0000000000000000000000000000000000000000..04a23ed38c6bdc32869baaf439bca4d46a724060 GIT binary patch literal 759 zcmb7?%TC)s6o&svoY--k5H1OU5C|8c6sbfiOHen6E~m;Eg+Ag z3k#ly3Q8WfQ1h^jvOu=|p)XKvcdz9S+3{s~)#)X%4zCVPyw<*Wdn13OL!EpUu#Tfk zB~Ut!!cii_q%Zw3*Y3&Bp}I*lqty61iUsDnI#j3QV4&hNIq;cOov?M(`A)@zx=IFz z0_AQrlzv~v+T;=7_M&k-RA03D$~se{M8GkI;7=5vy8EUGfyK0zS*$?iUxnWW*J?<{ zf1%#5QKACU1F1uSoH0bF_JAcsW9Hj8=A3?rO}0A+^H?Zg19K3V=jsF*dO-CzoQ2Fi z3b(M%jW6imrCSb)OknYxYbhj4&w@jw$N#hho5 ()V' { + 4 6 + 8 6 + 1a 6 + 1b 6 + 1c 6 + 1d 6 + 1e 6 + 1f 6 + 20 7 + } + + method 'bar (Ljava/lang/Class;)Lcfrtest/Java14Test;' { + 7 10 + } + + method 'instance ()Lcfrtest/Java14Test;' { + 3 14 + 15 14 + 16 14 + 17 14 + 18 14 + } + + method 'getAClass ()Ljava/lang/Class;' { + 3 18 + 15 18 + } +} + +Lines mapping: +7 <-> 11 +11 <-> 15 +12 <-> 7 +14 <-> 19 +Not mapped: +3 diff --git a/testData/results/JsHurt.dec b/testData/results/JsHurt.dec new file mode 100644 index 0000000000..a6faec0eeb --- /dev/null +++ b/testData/results/JsHurt.dec @@ -0,0 +1,36 @@ +public class JsHurt { + public static void main(String[] var0) { + int var1 = 0; + + while(true) { + System.out.println(var1); + if (var1 >= 20) { + return; + } + + ++var1; + } + } +} + +class 'JsHurt' { + method 'main ([Ljava/lang/String;)V' { + 0 2 + 1 2 + 5 10 + c 5 + d 5 + e 5 + f 5 + 10 5 + 11 5 + 12 5 + 13 6 + 14 6 + 15 6 + 16 6 + 1c 7 + } +} + +Lines mapping: diff --git a/testData/results/TestJsr.dec b/testData/results/TestJsr.dec new file mode 100644 index 0000000000..b141d8572f --- /dev/null +++ b/testData/results/TestJsr.dec @@ -0,0 +1,34 @@ +public class TestJsr { + public static void main(String[] var0) { + try { + System.out.println("Test");// 3 4 + } finally { + System.out.println("Jsr"); + } + + }// 6 +} + +class 'TestJsr' { + method 'main ([Ljava/lang/String;)V' { + 0 3 + 1 3 + 2 3 + 3 3 + 4 3 + 5 3 + c 5 + d 5 + e 5 + f 5 + 10 5 + 11 5 + 12 5 + 18 8 + } +} + +Lines mapping: +3 <-> 4 +4 <-> 4 +6 <-> 9 diff --git a/testData/results/TestJsr2.dec b/testData/results/TestJsr2.dec new file mode 100644 index 0000000000..4d37db61eb --- /dev/null +++ b/testData/results/TestJsr2.dec @@ -0,0 +1,139 @@ +public class TestJsr2 { + public static void main(String[] var0) { + try { + System.out.println("Test");// 3 4 + } finally { + ; + } + + System.out.println("Jsr");// 6 + }// 7 + + public static void main2(String[] var0) { + try { + try { + System.out.println("Test");// 12 13 14 + } finally { + ; + } + + System.out.println("Jsr");// 16 + } finally { + ; + } + + System.out.println("Jsr");// 20 + }// 21 + + public static void main3(String[] var0) { + try { + try { + System.out.println("Test");// 26 27 28 + } finally { + ; + } + + System.out.println("Jsr");// 31 + } finally { + ; + } + + System.out.println("Jsr");// 35 + }// 36 +} + +class 'TestJsr2' { + method 'main ([Ljava/lang/String;)V' { + 0 3 + 1 3 + 2 3 + 3 3 + 4 3 + 5 3 + c 8 + d 8 + e 8 + f 8 + 10 8 + 11 8 + 12 8 + 13 8 + 14 9 + } + + method 'main2 ([Ljava/lang/String;)V' { + 0 14 + 1 14 + 2 14 + 3 14 + 4 14 + 5 14 + c 19 + d 19 + e 19 + f 19 + 10 19 + 11 19 + 12 19 + 13 19 + 18 24 + 19 24 + 1a 24 + 1b 24 + 1c 24 + 1d 24 + 1e 24 + 1f 24 + 20 25 + } + + method 'main3 ([Ljava/lang/String;)V' { + 0 30 + 1 30 + 2 30 + 3 30 + 4 30 + 5 30 + 6 30 + 7 30 + c 35 + d 35 + e 35 + f 35 + 10 35 + 11 35 + 12 35 + 13 35 + 18 40 + 19 40 + 1a 40 + 1b 40 + 1c 40 + 1d 40 + 1e 40 + 1f 40 + 20 41 + } +} + +Lines mapping: +3 <-> 4 +4 <-> 4 +6 <-> 9 +7 <-> 10 +12 <-> 15 +13 <-> 15 +14 <-> 15 +16 <-> 20 +20 <-> 25 +21 <-> 26 +26 <-> 31 +27 <-> 31 +28 <-> 31 +31 <-> 36 +35 <-> 41 +36 <-> 42 +Not mapped: +17 +29 +32 From 7991d6d59536367811e5979dfe47cd17b6883f80 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 16 Nov 2021 20:51:51 -0500 Subject: [PATCH 23/85] Add override annotation toggle --- src/org/jetbrains/java/decompiler/main/ClassWriter.java | 2 +- .../java/decompiler/main/extern/IFernflowerPreferences.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 6583b7879b..6f24e5c1d6 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -819,7 +819,7 @@ private boolean methodToJava(ClassNode node, StructMethod mt, int methodIndex, T appendAnnotations(buffer, indent, mt, TypeAnnotation.METHOD_RETURN_TYPE); // Try append @Override after all other annotations - if (mt.getBytecodeVersion().hasOverride() && !CodeConstants.INIT_NAME.equals(mt.getName()) && !CodeConstants.CLINIT_NAME.equals(mt.getName()) && !mt.hasModifier(CodeConstants.ACC_STATIC) && !mt.hasModifier(CodeConstants.ACC_PRIVATE)) { + if (DecompilerContext.getOption(IFernflowerPreferences.OVERRIDE_ANNOTATION) && mt.getBytecodeVersion().hasOverride() && !CodeConstants.INIT_NAME.equals(mt.getName()) && !CodeConstants.CLINIT_NAME.equals(mt.getName()) && !mt.hasModifier(CodeConstants.ACC_STATIC) && !mt.hasModifier(CodeConstants.ACC_PRIVATE)) { // Search superclasses for methods that match the name and descriptor of this one. // Make sure not to search the current class otherwise it will return the current method itself! // TODO: record overrides diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java index 31ee18a40e..4994414926 100644 --- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java +++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java @@ -38,6 +38,7 @@ public interface IFernflowerPreferences { String PATTERN_MATCHING = "pam"; String EXPERIMENTAL_TRY_LOOP_FIX = "tlf"; String TERNARY_CONDITIONS = "tco"; + String OVERRIDE_ANNOTATION = "ovr"; String INCLUDE_ENTIRE_CLASSPATH = "iec"; String INCLUDE_JAVA_RUNTIME = "jrt"; @@ -100,6 +101,7 @@ static Map getDefaults() { defaults.put(IGNORE_INVALID_BYTECODE, "0"); defaults.put(VERIFY_ANONYMOUS_CLASSES, "0"); defaults.put(TERNARY_CONSTANT_SIMPLIFICATION, "0"); + defaults.put(OVERRIDE_ANNOTATION, "1"); defaults.put(PATTERN_MATCHING, "0"); // Pattern matching has some issues around negative blocks defaults.put(EXPERIMENTAL_TRY_LOOP_FIX, "0"); // Causes issues when decompiling certain classes defaults.put(TERNARY_CONDITIONS, "1"); // Ternary conditions are pretty stable so they can go in here From 2782ceffc1c9f0ab1f43bf61b095fb68205ed5a6 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Wed, 17 Nov 2021 08:07:42 -0500 Subject: [PATCH 24/85] Few more tests --- .../decompiler/SecondaryFunctionsHelper.java | 5 +- .../java/decompiler/SingleClassesTest.java | 4 + testData/classes/custom/TestIdeaNotNull.class | Bin 0 -> 2120 bytes testData/results/TestIdeaNotNull.dec | 103 ++++++++++++++++++ testData/results/pkg/TestOverrideIndirect.dec | 43 ++++++++ .../src/java8/pkg/TestOverrideIndirect.java | 29 +++++ 6 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 testData/classes/custom/TestIdeaNotNull.class create mode 100644 testData/results/TestIdeaNotNull.dec create mode 100644 testData/results/pkg/TestOverrideIndirect.dec create mode 100644 testData/src/java8/pkg/TestOverrideIndirect.java diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java index cc27d63218..72de2c7663 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java @@ -85,6 +85,7 @@ public static boolean identifySecondaryFunctions(Statement stat, VarProcessor va } } + boolean ret = false; boolean replaced = true; while (replaced) { replaced = false; @@ -96,6 +97,7 @@ public static boolean identifySecondaryFunctions(Statement stat, VarProcessor va if (obj instanceof Statement) { if (identifySecondaryFunctions((Statement)obj, varProc)) { + ret = true; replaced = true; break; } @@ -110,6 +112,7 @@ else if (obj instanceof Exprent) { else { stat.getExprents().set(i, retexpr); } + ret = true; replaced = true; break; } @@ -117,7 +120,7 @@ else if (obj instanceof Exprent) { } } - return false; + return ret; } private static Exprent identifySecondaryFunctions(Exprent exprent, boolean statement_level, VarProcessor varProc) { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 049ff8f973..eb6a97c505 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -387,7 +387,11 @@ private void registerDefault() { registerRaw(CUSTOM, "Java14Test"); // Used from CFR registerRaw(CUSTOM, "JsHurt"); // Used from CFR registerRaw(CUSTOM, "TestJsr"); + // TODO: Returns not processing properly registerRaw(CUSTOM, "TestJsr2"); + register(JAVA_8, "TestOverrideIndirect"); + // TODO: IdeaNotNullHelper doesn't seem to be doing anything + registerRaw(CUSTOM, "TestIdeaNotNull"); } private void registerEntireClassPath() { diff --git a/testData/classes/custom/TestIdeaNotNull.class b/testData/classes/custom/TestIdeaNotNull.class new file mode 100644 index 0000000000000000000000000000000000000000..5e097870f362f2f49903289ebbf087d879cd9e01 GIT binary patch literal 2120 zcmb7ET~ixX7=BJR$u3KP5WXx8u!SIBmbA9oA}y9uDyb=@fN0vzI7`^l#bh_L*>u`_ ze}$J`m>I9s3+TwGm(Fw?`7AT;%=@1AocH5A@5k9c{`vV=0N3$MM?1ze zjH{T?p6x}u&6>;wDlQGs`SB}St zN$ghzdd5#flNHOHjId&QX4&#B?-(3?&8>Mw>%J|E*?po!)3PcFbRa1Jfn-pmns1k~ ztERK%mJ|38Hw5}l7VmD&F0tkb+{BDzA0;r0J{7kTxQ#g#A181JBLeC3`g3q!(3D4; zJ64gc3LzZnlYr`2ul$@tWpq3@!G6WfO2u-v1TLRdnp4$kf@Qs# z`c|29>edLMC-k@7>aF3>}V5u2izN%@W^|Z!NwmS{3` z(2G9)@uc&gw2pFJN=5SfPzrm9CKJ1e-A;dlwyDDJP?a~h_k%Jwkp33weZ*;@PVGWV z@1kWFdj4xg)Ej>VmQiWRSPBNn2M}wJDJt4j3=$$a{)P|(OHz^$hoO)&kMX#UN!! zs%#85NnO4a%B;B9LyQv8=>MJ^gdctqj+7-Csrz+ksiiuU!0JM165K3hNdvJu)Hp4E zL3=Y4OAvlCmXsxB3Q8)sR!1w>2VBF5XWu(gh^9UbY@>nCdA5TxWGt1JA>Ux-tvECL zSbg&49@gt<-^Yd&Kc~xYgeHPP`3|Xc^d4uTKw2O**a9ICp(q+`Xj4{EXh1z@$3Y0a X{- 9 +11 <-> 10 +13 <-> 11 +14 <-> 12 +17 <-> 18 +18 <-> 19 +21 <-> 22 +25 <-> 35 +26 <-> 36 diff --git a/testData/results/pkg/TestOverrideIndirect.dec b/testData/results/pkg/TestOverrideIndirect.dec new file mode 100644 index 0000000000..92d1d80bfa --- /dev/null +++ b/testData/results/pkg/TestOverrideIndirect.dec @@ -0,0 +1,43 @@ +package pkg; + +import java.util.function.Function; + +public class TestOverrideIndirect { + public interface A { + } + + public interface B { + } + + public interface Magic extends Function { + String name(); + } + + public class Sparkles implements TestOverrideIndirect.Magic { + @Override + public String name() { + return "Sparkles";// 21 + } + + public TestOverrideIndirect.B apply(TestOverrideIndirect.A a) { + return null;// 26 + } + } +} + +class 'pkg/TestOverrideIndirect$Sparkles' { + method 'name ()Ljava/lang/String;' { + 0 18 + 1 18 + 2 18 + } + + method 'apply (Lpkg/TestOverrideIndirect$A;)Lpkg/TestOverrideIndirect$B;' { + 0 22 + 1 22 + } +} + +Lines mapping: +21 <-> 19 +26 <-> 23 diff --git a/testData/src/java8/pkg/TestOverrideIndirect.java b/testData/src/java8/pkg/TestOverrideIndirect.java new file mode 100644 index 0000000000..cd4dafc973 --- /dev/null +++ b/testData/src/java8/pkg/TestOverrideIndirect.java @@ -0,0 +1,29 @@ +package pkg; + +import java.util.function.Function; + +public class TestOverrideIndirect { + public interface A { + + } + + public interface B { + + } + + public interface Magic extends Function { + String name(); + } + + public class Sparkles implements Magic { + @Override + public String name() { + return "Sparkles"; + } + + @Override + public B apply(A a) { + return null; + } + } +} From b52eaa777f526b3e701f3976fbf04b94eaa85ba2 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Wed, 17 Nov 2021 08:19:54 -0500 Subject: [PATCH 25/85] Re-add disabled tests --- .../java/decompiler/SingleClassesTest.java | 4 +- testData/results/pkg/TestLVTComplex.dec | 82 ++++ testData/results/pkg/TestPPMM.dec | 353 +++--------------- 3 files changed, 132 insertions(+), 307 deletions(-) create mode 100644 testData/results/pkg/TestLVTComplex.dec diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index eb6a97c505..f03d4204bb 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -466,11 +466,11 @@ private void registerLVT() { register(JAVA_8, "TestLVT"); register(JAVA_8, "TestLVTScoping"); // TODO: int is decompiling as - // register(JAVA_8, "TestLVTComplex"); + register(JAVA_8, "TestLVTComplex"); register(JAVA_8, "TestVarType"); register(JAVA_8, "TestLoopMerging"); // TODO: this is not decompiling properly, needs a look - // register(JAVA_8, "TestPPMM"); + register(JAVA_8, "TestPPMM"); } private void registerTryLoop() { diff --git a/testData/results/pkg/TestLVTComplex.dec b/testData/results/pkg/TestLVTComplex.dec new file mode 100644 index 0000000000..4159d89feb --- /dev/null +++ b/testData/results/pkg/TestLVTComplex.dec @@ -0,0 +1,82 @@ +package pkg; + +import java.util.ArrayList; + +public class TestLVTComplex { + public static void main() { + int[] x = new int[5]; + + for( var10000_1 : x) { + ; + } + + for( var23_1 : x) { + System.out.println("asdf"); + } + + ArrayList x1 = new ArrayList(); + + for( var18_1 : x1) { + ; + } + + for(Object y : x1) { + int[] x2 = new int[10]; + + for( var24_1 : x2) { + ; + } + + for( var25_1 : x2) { + System.out.println("asdf"); + } + + System.out.println("asdf"); + } + + switch(TestLVTComplex.Bob.HI) { + case HI: + System.out.println("HI"); + break; + case LO: + System.out.println("LO"); + } + + if (TestLVTComplex.Bob.HI == TestLVTComplex.Bob.HI) { + String var14 = "a"; + } else { + String var15 = "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( var10000_1 : values()) { + if (b == c) { + System.out.println("Asdf"); + } + } + } + } + + } + } +} diff --git a/testData/results/pkg/TestPPMM.dec b/testData/results/pkg/TestPPMM.dec index c5f22f39b0..960788adb8 100644 --- a/testData/results/pkg/TestPPMM.dec +++ b/testData/results/pkg/TestPPMM.dec @@ -2,334 +2,77 @@ package pkg; public class TestPPMM { public void ipp() { - int a = 0;// 22 - ++a;// 23 - ++a;// 24 - ++a;// 25 - ++a;// 26 - }// 27 + int a = 0; + ++a; + ++a; + ++a; + ++a; + } public void ppi() { - int a = 0;// 29 - ++a;// 30 - ++a;// 31 - ++a;// 32 - ++a;// 33 - }// 34 + int a = 0; + ++a; + ++a; + ++a; + ++a; + } public void imm() { - int a = 0;// 36 - --a;// 37 - --a;// 38 - --a;// 39 - --a;// 40 - }// 41 + int a = 0; + --a; + --a; + --a; + --a; + } public void mmi() { - int a = 0;// 43 - --a;// 44 - --a;// 45 - --a;// 46 - --a;// 47 - }// 48 + int a = 0; + --a; + --a; + --a; + --a; + } public void ippf() { - int a = 0;// 52 - t(a++);// 53 - t(a++);// 54 - t(a++);// 55 - t(a++);// 56 - }// 57 + int a = 0; + t(a++); + t(a++); + t(a++); + t(a++); + } public void ppif() { - int a = 0;// 59 - ++a;// 60 + int a = 0; + ++a; t(a); - ++a;// 61 + ++a; t(a); - ++a;// 62 + ++a; t(a); - ++a;// 63 + ++a; t(a); - }// 64 + } public void immf() { - int a = 0;// 66 - t(a--);// 67 - t(a--);// 68 - t(a--);// 69 - t(a--);// 70 - }// 71 + int a = 0; + t(a--); + t(a--); + t(a--); + t(a--); + } public void mmif() { - int a = 0;// 73 - --a;// 74 + int a = 0; + --a; t(a); - --a;// 75 + --a; t(a); - --a;// 76 + --a; t(a); - --a;// 77 + --a; t(a); - }// 78 - - private static void t(int x) { - }// 80 -} - -class 'pkg/TestPPMM' { - method 'ipp ()V' { - 0 4 - 1 4 - 2 5 - 3 5 - 4 5 - 5 6 - 6 6 - 7 6 - 8 7 - 9 7 - a 7 - b 8 - c 8 - d 8 - e 9 } - method 'ppi ()V' { - 0 12 - 1 12 - 2 13 - 3 13 - 4 13 - 5 14 - 6 14 - 7 14 - 8 15 - 9 15 - a 15 - b 16 - c 16 - d 16 - e 17 - } - - method 'imm ()V' { - 0 20 - 1 20 - 2 21 - 3 21 - 4 21 - 5 22 - 6 22 - 7 22 - 8 23 - 9 23 - a 23 - b 24 - c 24 - d 24 - e 25 - } - - method 'mmi ()V' { - 0 28 - 1 28 - 2 29 - 3 29 - 4 29 - 5 30 - 6 30 - 7 30 - 8 31 - 9 31 - a 31 - b 32 - c 32 - d 32 - e 33 - } - - method 'ippf ()V' { - 0 36 - 1 36 - 3 37 - 4 37 - 5 37 - 6 37 - 7 37 - 8 37 - a 38 - b 38 - c 38 - d 38 - e 38 - f 38 - 11 39 - 12 39 - 13 39 - 14 39 - 15 39 - 16 39 - 18 40 - 19 40 - 1a 40 - 1b 40 - 1c 40 - 1d 40 - 1e 41 - } - - method 'ppif ()V' { - 0 44 - 1 44 - 2 45 - 3 45 - 4 45 - 5 46 - 6 46 - 7 46 - 8 46 - 9 47 - a 47 - b 47 - c 48 - d 48 - e 48 - f 48 - 10 49 - 11 49 - 12 49 - 13 50 - 14 50 - 15 50 - 16 50 - 17 51 - 18 51 - 19 51 - 1a 52 - 1b 52 - 1c 52 - 1d 52 - 1e 53 - } - - method 'immf ()V' { - 0 56 - 1 56 - 3 57 - 4 57 - 5 57 - 6 57 - 7 57 - 8 57 - a 58 - b 58 - c 58 - d 58 - e 58 - f 58 - 11 59 - 12 59 - 13 59 - 14 59 - 15 59 - 16 59 - 18 60 - 19 60 - 1a 60 - 1b 60 - 1c 60 - 1d 60 - 1e 61 - } - - method 'mmif ()V' { - 0 64 - 1 64 - 2 65 - 3 65 - 4 65 - 5 66 - 6 66 - 7 66 - 8 66 - 9 67 - a 67 - b 67 - c 68 - d 68 - e 68 - f 68 - 10 69 - 11 69 - 12 69 - 13 70 - 14 70 - 15 70 - 16 70 - 17 71 - 18 71 - 19 71 - 1a 72 - 1b 72 - 1c 72 - 1d 72 - 1e 73 - } - - method 't (I)V' { - 0 76 + private static void t(int x) { } } - -Lines mapping: -22 <-> 5 -23 <-> 6 -24 <-> 7 -25 <-> 8 -26 <-> 9 -27 <-> 10 -29 <-> 13 -30 <-> 14 -31 <-> 15 -32 <-> 16 -33 <-> 17 -34 <-> 18 -36 <-> 21 -37 <-> 22 -38 <-> 23 -39 <-> 24 -40 <-> 25 -41 <-> 26 -43 <-> 29 -44 <-> 30 -45 <-> 31 -46 <-> 32 -47 <-> 33 -48 <-> 34 -52 <-> 37 -53 <-> 38 -54 <-> 39 -55 <-> 40 -56 <-> 41 -57 <-> 42 -59 <-> 45 -60 <-> 46 -61 <-> 48 -62 <-> 50 -63 <-> 52 -64 <-> 54 -66 <-> 57 -67 <-> 58 -68 <-> 59 -69 <-> 60 -70 <-> 61 -71 <-> 62 -73 <-> 65 -74 <-> 66 -75 <-> 68 -76 <-> 70 -77 <-> 72 -78 <-> 74 -80 <-> 77 From d2336b39c1ed2575446eea61326d4bc4ceaceec3 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Wed, 17 Nov 2021 08:22:40 -0500 Subject: [PATCH 26/85] Remove duplicated test --- test/org/jetbrains/java/decompiler/SingleClassesTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index f03d4204bb..cdae215157 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -469,8 +469,6 @@ private void registerLVT() { register(JAVA_8, "TestLVTComplex"); register(JAVA_8, "TestVarType"); register(JAVA_8, "TestLoopMerging"); - // TODO: this is not decompiling properly, needs a look - register(JAVA_8, "TestPPMM"); } private void registerTryLoop() { From 5322b81b81ed821082bf53a44bb22b1aca3c8688 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Wed, 17 Nov 2021 09:31:00 -0500 Subject: [PATCH 27/85] Add back line number info --- testData/results/pkg/TestPPMM.dec | 353 ++++++++++++++++++++++++++---- 1 file changed, 305 insertions(+), 48 deletions(-) diff --git a/testData/results/pkg/TestPPMM.dec b/testData/results/pkg/TestPPMM.dec index 960788adb8..c5f22f39b0 100644 --- a/testData/results/pkg/TestPPMM.dec +++ b/testData/results/pkg/TestPPMM.dec @@ -2,77 +2,334 @@ package pkg; public class TestPPMM { public void ipp() { - int a = 0; - ++a; - ++a; - ++a; - ++a; - } + int a = 0;// 22 + ++a;// 23 + ++a;// 24 + ++a;// 25 + ++a;// 26 + }// 27 public void ppi() { - int a = 0; - ++a; - ++a; - ++a; - ++a; - } + int a = 0;// 29 + ++a;// 30 + ++a;// 31 + ++a;// 32 + ++a;// 33 + }// 34 public void imm() { - int a = 0; - --a; - --a; - --a; - --a; - } + int a = 0;// 36 + --a;// 37 + --a;// 38 + --a;// 39 + --a;// 40 + }// 41 public void mmi() { - int a = 0; - --a; - --a; - --a; - --a; - } + int a = 0;// 43 + --a;// 44 + --a;// 45 + --a;// 46 + --a;// 47 + }// 48 public void ippf() { - int a = 0; - t(a++); - t(a++); - t(a++); - t(a++); - } + int a = 0;// 52 + t(a++);// 53 + t(a++);// 54 + t(a++);// 55 + t(a++);// 56 + }// 57 public void ppif() { - int a = 0; - ++a; + int a = 0;// 59 + ++a;// 60 t(a); - ++a; + ++a;// 61 t(a); - ++a; + ++a;// 62 t(a); - ++a; + ++a;// 63 t(a); - } + }// 64 public void immf() { - int a = 0; - t(a--); - t(a--); - t(a--); - t(a--); - } + int a = 0;// 66 + t(a--);// 67 + t(a--);// 68 + t(a--);// 69 + t(a--);// 70 + }// 71 public void mmif() { - int a = 0; - --a; + int a = 0;// 73 + --a;// 74 t(a); - --a; + --a;// 75 t(a); - --a; + --a;// 76 t(a); - --a; + --a;// 77 t(a); - } + }// 78 private static void t(int x) { + }// 80 +} + +class 'pkg/TestPPMM' { + method 'ipp ()V' { + 0 4 + 1 4 + 2 5 + 3 5 + 4 5 + 5 6 + 6 6 + 7 6 + 8 7 + 9 7 + a 7 + b 8 + c 8 + d 8 + e 9 + } + + method 'ppi ()V' { + 0 12 + 1 12 + 2 13 + 3 13 + 4 13 + 5 14 + 6 14 + 7 14 + 8 15 + 9 15 + a 15 + b 16 + c 16 + d 16 + e 17 + } + + method 'imm ()V' { + 0 20 + 1 20 + 2 21 + 3 21 + 4 21 + 5 22 + 6 22 + 7 22 + 8 23 + 9 23 + a 23 + b 24 + c 24 + d 24 + e 25 + } + + method 'mmi ()V' { + 0 28 + 1 28 + 2 29 + 3 29 + 4 29 + 5 30 + 6 30 + 7 30 + 8 31 + 9 31 + a 31 + b 32 + c 32 + d 32 + e 33 + } + + method 'ippf ()V' { + 0 36 + 1 36 + 3 37 + 4 37 + 5 37 + 6 37 + 7 37 + 8 37 + a 38 + b 38 + c 38 + d 38 + e 38 + f 38 + 11 39 + 12 39 + 13 39 + 14 39 + 15 39 + 16 39 + 18 40 + 19 40 + 1a 40 + 1b 40 + 1c 40 + 1d 40 + 1e 41 + } + + method 'ppif ()V' { + 0 44 + 1 44 + 2 45 + 3 45 + 4 45 + 5 46 + 6 46 + 7 46 + 8 46 + 9 47 + a 47 + b 47 + c 48 + d 48 + e 48 + f 48 + 10 49 + 11 49 + 12 49 + 13 50 + 14 50 + 15 50 + 16 50 + 17 51 + 18 51 + 19 51 + 1a 52 + 1b 52 + 1c 52 + 1d 52 + 1e 53 + } + + method 'immf ()V' { + 0 56 + 1 56 + 3 57 + 4 57 + 5 57 + 6 57 + 7 57 + 8 57 + a 58 + b 58 + c 58 + d 58 + e 58 + f 58 + 11 59 + 12 59 + 13 59 + 14 59 + 15 59 + 16 59 + 18 60 + 19 60 + 1a 60 + 1b 60 + 1c 60 + 1d 60 + 1e 61 + } + + method 'mmif ()V' { + 0 64 + 1 64 + 2 65 + 3 65 + 4 65 + 5 66 + 6 66 + 7 66 + 8 66 + 9 67 + a 67 + b 67 + c 68 + d 68 + e 68 + f 68 + 10 69 + 11 69 + 12 69 + 13 70 + 14 70 + 15 70 + 16 70 + 17 71 + 18 71 + 19 71 + 1a 72 + 1b 72 + 1c 72 + 1d 72 + 1e 73 + } + + method 't (I)V' { + 0 76 } } + +Lines mapping: +22 <-> 5 +23 <-> 6 +24 <-> 7 +25 <-> 8 +26 <-> 9 +27 <-> 10 +29 <-> 13 +30 <-> 14 +31 <-> 15 +32 <-> 16 +33 <-> 17 +34 <-> 18 +36 <-> 21 +37 <-> 22 +38 <-> 23 +39 <-> 24 +40 <-> 25 +41 <-> 26 +43 <-> 29 +44 <-> 30 +45 <-> 31 +46 <-> 32 +47 <-> 33 +48 <-> 34 +52 <-> 37 +53 <-> 38 +54 <-> 39 +55 <-> 40 +56 <-> 41 +57 <-> 42 +59 <-> 45 +60 <-> 46 +61 <-> 48 +62 <-> 50 +63 <-> 52 +64 <-> 54 +66 <-> 57 +67 <-> 58 +68 <-> 59 +69 <-> 60 +70 <-> 61 +71 <-> 62 +73 <-> 65 +74 <-> 66 +75 <-> 68 +76 <-> 70 +77 <-> 72 +78 <-> 74 +80 <-> 77 From dc1b2083421a39ce943a166ac2050db5d42252e0 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Wed, 17 Nov 2021 12:05:18 -0500 Subject: [PATCH 28/85] Refactor attributes to have bytecode version, add hotjava tests and other source --- .../java/decompiler/code/BytecodeVersion.java | 4 + .../java/decompiler/struct/StructClass.java | 4 +- .../java/decompiler/struct/StructField.java | 20 ++- .../java/decompiler/struct/StructMember.java | 13 +- .../java/decompiler/struct/StructMethod.java | 7 +- .../struct/StructRecordComponent.java | 11 +- .../attr/StructAnnDefaultAttribute.java | 3 +- .../attr/StructAnnotationAttribute.java | 3 +- .../StructAnnotationParameterAttribute.java | 3 +- .../attr/StructBootstrapMethodsAttribute.java | 3 +- .../struct/attr/StructCodeAttribute.java | 13 +- .../attr/StructConstantValueAttribute.java | 3 +- .../attr/StructEnclosingMethodAttribute.java | 3 +- .../attr/StructExceptionsAttribute.java | 3 +- .../struct/attr/StructGeneralAttribute.java | 3 +- .../attr/StructGenericSignatureAttribute.java | 3 +- .../attr/StructInnerClassesAttribute.java | 3 +- .../attr/StructLineNumberTableAttribute.java | 3 +- .../StructLocalVariableTableAttribute.java | 3 +- ...StructLocalVariableTypeTableAttribute.java | 5 +- .../attr/StructMethodParametersAttribute.java | 3 +- .../struct/attr/StructModuleAttribute.java | 3 +- .../StructPermittedSubclassesAttribute.java | 3 +- .../struct/attr/StructRecordAttribute.java | 5 +- .../attr/StructTypeAnnotationAttribute.java | 3 +- .../java/decompiler/SingleClassesTest.java | 2 + testData/classes/custom/TestHotjava.class | Bin 0 -> 988 bytes .../classes/custom/source/TestHotjava.java | 35 +++++ testData/classes/custom/source/TestJsr.java | 9 ++ testData/classes/custom/source/TestJsr2.java | 39 +++++ testData/results/TestHotjava.dec | 145 ++++++++++++++++++ 31 files changed, 316 insertions(+), 44 deletions(-) create mode 100644 testData/classes/custom/TestHotjava.class create mode 100644 testData/classes/custom/source/TestHotjava.java create mode 100644 testData/classes/custom/source/TestJsr.java create mode 100644 testData/classes/custom/source/TestJsr2.java create mode 100644 testData/results/TestHotjava.dec diff --git a/src/org/jetbrains/java/decompiler/code/BytecodeVersion.java b/src/org/jetbrains/java/decompiler/code/BytecodeVersion.java index 82a398c233..8eca1af35b 100644 --- a/src/org/jetbrains/java/decompiler/code/BytecodeVersion.java +++ b/src/org/jetbrains/java/decompiler/code/BytecodeVersion.java @@ -50,6 +50,10 @@ public boolean hasNewTryWithResources() { return major >= MAJOR_11; } + public boolean predatesJava() { + return major <= MAJOR_1_0_2 && minor <= 2; + } + private boolean previewFrom(int previewStart) { return major >= previewStart && minor == PREVIEW; } diff --git a/src/org/jetbrains/java/decompiler/struct/StructClass.java b/src/org/jetbrains/java/decompiler/struct/StructClass.java index abb2f2c687..65d7e05341 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructClass.java +++ b/src/org/jetbrains/java/decompiler/struct/StructClass.java @@ -76,7 +76,7 @@ public static StructClass create(DataInputFullStream in, boolean own, LazyLoader length = in.readUnsignedShort(); VBStyleCollectionfields = new VBStyleCollection<>(length); for (int i = 0; i < length; i++) { - StructField field = StructField.create(in, pool, qualifiedName); + StructField field = StructField.create(in, pool, qualifiedName, bytecodeVersion); fields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor())); } @@ -92,7 +92,7 @@ public static StructClass create(DataInputFullStream in, boolean own, LazyLoader methods.addWithKey(method, key); } - Map attributes = readAttributes(in, pool); + Map attributes = readAttributes(in, pool, bytecodeVersion); GenericClassDescriptor signature = null; if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { diff --git a/src/org/jetbrains/java/decompiler/struct/StructField.java b/src/org/jetbrains/java/decompiler/struct/StructField.java index 232f47dd8d..53f04374f4 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructField.java +++ b/src/org/jetbrains/java/decompiler/struct/StructField.java @@ -1,6 +1,7 @@ // 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.code.BytecodeVersion; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; @@ -24,14 +25,14 @@ } */ public class StructField extends StructMember { - public static StructField create(DataInputFullStream in, ConstantPool pool, String clQualifiedName) throws IOException { + public static StructField create(DataInputFullStream in, ConstantPool pool, String clQualifiedName, BytecodeVersion version) throws IOException { int accessFlags = in.readUnsignedShort(); int nameIndex = in.readUnsignedShort(); int descriptorIndex = in.readUnsignedShort(); String[] values = pool.getClassElement(ConstantPool.FIELD, clQualifiedName, nameIndex, descriptorIndex); - Map attributes = readAttributes(in, pool); + Map attributes = readAttributes(in, pool, version); GenericFieldDescriptor signature = null; if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { StructGenericSignatureAttribute signatureAttr = (StructGenericSignatureAttribute)attributes.get(StructGeneralAttribute.ATTRIBUTE_SIGNATURE.name); @@ -40,22 +41,24 @@ public static StructField create(DataInputFullStream in, ConstantPool pool, Stri } } - return new StructField(accessFlags, attributes, values[0], values[1], signature); + return new StructField(accessFlags, attributes, values[0], values[1], signature, version); } private final String name; private final String descriptor; private final GenericFieldDescriptor signature; + private final BytecodeVersion version; - 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, BytecodeVersion version) { + this(accessFlags, attributes, name, descriptor, null, version); } - protected StructField(int accessFlags, Map attributes, String name, String descriptor, GenericFieldDescriptor signature) { + protected StructField(int accessFlags, Map attributes, String name, String descriptor, GenericFieldDescriptor signature, BytecodeVersion version) { super(accessFlags, attributes); this.name = name; this.descriptor = descriptor; this.signature = signature; + this.version = version; } public final String getName() { @@ -74,4 +77,9 @@ public String toString() { public GenericFieldDescriptor getSignature() { return signature; } + + @Override + protected BytecodeVersion getVersion() { + return this.version; + } } diff --git a/src/org/jetbrains/java/decompiler/struct/StructMember.java b/src/org/jetbrains/java/decompiler/struct/StructMember.java index 9ef658d616..f81d5857f5 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructMember.java +++ b/src/org/jetbrains/java/decompiler/struct/StructMember.java @@ -1,6 +1,7 @@ // 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.code.BytecodeVersion; import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.struct.attr.StructCodeAttribute; import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; @@ -45,11 +46,11 @@ public boolean isSynthetic() { return hasModifier(CodeConstants.ACC_SYNTHETIC) || hasAttribute(StructGeneralAttribute.ATTRIBUTE_SYNTHETIC); } - public static Map readAttributes(DataInputFullStream in, ConstantPool pool) throws IOException { - return readAttributes(in, pool, true); + public static Map readAttributes(DataInputFullStream in, ConstantPool pool, BytecodeVersion version) throws IOException { + return readAttributes(in, pool, true, version); } - public static Map readAttributes(DataInputFullStream in, ConstantPool pool, boolean readCode) throws IOException { + public static Map readAttributes(DataInputFullStream in, ConstantPool pool, boolean readCode, BytecodeVersion version) throws IOException { int length = in.readUnsignedShort(); Map attributes = new HashMap<>(length); @@ -63,7 +64,7 @@ public static Map readAttributes(DataInputFullSt in.discard(attLength); } else { - attribute.initContent(in, pool); + attribute.initContent(in, pool, version); if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.name.equals(name) && attributes.containsKey(name)) { // merge all variable tables StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.get(name); @@ -85,6 +86,8 @@ else if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.name.equals( return attributes; } + protected abstract BytecodeVersion getVersion(); + protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException { StructGeneralAttribute attribute = StructGeneralAttribute.createAttribute(name); int length = in.readInt(); @@ -92,7 +95,7 @@ protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantP in.discard(length); } else { - attribute.initContent(in, pool); + attribute.initContent(in, pool, getVersion()); } return attribute; } diff --git a/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/src/org/jetbrains/java/decompiler/struct/StructMethod.java index b78a29ff77..4b7a215fc2 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructMethod.java +++ b/src/org/jetbrains/java/decompiler/struct/StructMethod.java @@ -39,7 +39,7 @@ public static StructMethod create(DataInputFullStream in, ConstantPool pool, Str String[] values = pool.getClassElement(ConstantPool.METHOD, clQualifiedName, nameIndex, descriptorIndex); - Map attributes = readAttributes(in, pool, own); + Map attributes = readAttributes(in, pool, own, bytecodeVersion); StructCodeAttribute code = (StructCodeAttribute)attributes.remove(StructGeneralAttribute.ATTRIBUTE_CODE.name); if (code != null) { attributes.putAll(code.codeAttributes); @@ -382,6 +382,11 @@ public InstructionSequence getInstructionSequence() { return seq; } + @Override + protected BytecodeVersion getVersion() { + return this.bytecodeVersion; + } + public IVariableNameProvider getVariableNamer() { if (renamer == null) { this.renamer = DecompilerContext.getNamingFactory().createFactory(this); diff --git a/src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java b/src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java index 11fa1a3e62..4139b0007b 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java +++ b/src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java @@ -1,6 +1,7 @@ // 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.code.BytecodeVersion; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; @@ -23,14 +24,14 @@ } */ public class StructRecordComponent extends StructField { - public static StructRecordComponent create(DataInputFullStream in, ConstantPool pool) throws IOException { + public static StructRecordComponent create(DataInputFullStream in, ConstantPool pool, BytecodeVersion version) throws IOException { int nameIndex = in.readUnsignedShort(); int descriptorIndex = in.readUnsignedShort(); String name = ((PrimitiveConstant)pool.getConstant(nameIndex)).getString(); String descriptor = ((PrimitiveConstant)pool.getConstant(descriptorIndex)).getString(); - Map attributes = readAttributes(in, pool); + Map attributes = readAttributes(in, pool, version); GenericFieldDescriptor signature = null; if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { StructGenericSignatureAttribute signatureAttr = (StructGenericSignatureAttribute)attributes.get(StructGeneralAttribute.ATTRIBUTE_SIGNATURE.name); @@ -39,10 +40,10 @@ public static StructRecordComponent create(DataInputFullStream in, ConstantPool } } - return new StructRecordComponent(0, attributes, name, descriptor, signature); + return new StructRecordComponent(0, attributes, name, descriptor, signature, version); } - private StructRecordComponent(int flags, Map attributes, String name, String descriptor, GenericFieldDescriptor signature) { - super(flags, attributes, name, descriptor, signature); + private StructRecordComponent(int flags, Map attributes, String name, String descriptor, GenericFieldDescriptor signature, BytecodeVersion version) { + super(flags, attributes, name, descriptor, signature, version); } } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java index 891ffbace9..63ce3af011 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -12,7 +13,7 @@ public class StructAnnDefaultAttribute extends StructGeneralAttribute { private Exprent defaultValue; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { defaultValue = StructAnnotationAttribute.parseAnnotationElement(data, pool); } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java index dec6b28d00..55c2e2aab4 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; @@ -19,7 +20,7 @@ public class StructAnnotationAttribute extends StructGeneralAttribute { private List annotations; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { annotations = parseAnnotations(pool, data); } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java index d3f0de584e..3013f9393b 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -15,7 +16,7 @@ public class StructAnnotationParameterAttribute extends StructGeneralAttribute { private List> paramAnnotations; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int len = data.readUnsignedByte(); if (len > 0) { paramAnnotations = new ArrayList<>(len); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java index f97417ec22..6a8f58b4df 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.LinkConstant; import org.jetbrains.java.decompiler.struct.consts.PooledConstant; @@ -16,7 +17,7 @@ public class StructBootstrapMethodsAttribute extends StructGeneralAttribute { private final List> methodArguments = new ArrayList<>(); @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int method_number = data.readUnsignedShort(); for (int i = 0; i < method_number; ++i) { diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructCodeAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructCodeAttribute.java index 3bd0b0c3fd..d9843774fd 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructCodeAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructCodeAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.StructMember; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -32,10 +33,12 @@ public class StructCodeAttribute extends StructGeneralAttribute { public Map codeAttributes; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { - data.discard(2); - localVariables = data.readUnsignedShort(); - byte[] codeData = new byte[data.readInt()]; + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { + // Pre-java oak class files have a u1 max stack, u1 max locals, and a u2 code length + boolean predatesJava = version.predatesJava(); + data.discard(predatesJava ? 1 : 2); + localVariables = predatesJava ? data.readUnsignedByte() : data.readUnsignedShort(); + byte[] codeData = new byte[predatesJava ? data.readUnsignedShort() : data.readInt()]; data.readFully(codeData); int excLength = data.readUnsignedShort(); byte[] exceptionData = new byte[excLength * 8]; @@ -47,6 +50,6 @@ public void initContent(DataInputFullStream data, ConstantPool pool) throws IOEx d.writeShort(excLength); d.write(exceptionData); codeAndExceptionData = baos.toByteArray(); - codeAttributes = StructMember.readAttributes(data, pool); + codeAttributes = StructMember.readAttributes(data, pool, version); } } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java index a7e5cc15ae..17d3810f60 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -11,7 +12,7 @@ public class StructConstantValueAttribute extends StructGeneralAttribute { private int index; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { index = data.readUnsignedShort(); } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java index a886b9803d..472d165792 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.LinkConstant; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -14,7 +15,7 @@ public class StructEnclosingMethodAttribute extends StructGeneralAttribute { private String methodDescriptor; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int classIndex = data.readUnsignedShort(); int methodIndex = data.readUnsignedShort(); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java index a39d902f04..0ab2aca60f 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -14,7 +15,7 @@ public class StructExceptionsAttribute extends StructGeneralAttribute { private List throwsExceptions; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int len = data.readUnsignedShort(); if (len > 0) { throwsExceptions = new ArrayList<>(len); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java index f335b63433..7fcf541bfd 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -110,5 +111,5 @@ else if (ATTRIBUTE_PERMITTED_SUBCLASSES.name.equals(name)) { } } - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { } + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { } } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java index d3de8321f1..bf3e82e3a9 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -11,7 +12,7 @@ public class StructGenericSignatureAttribute extends StructGeneralAttribute { private String signature; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int index = data.readUnsignedShort(); signature = pool.getPrimitiveConstant(index).getString(); } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java index 238900d267..2ef03c7ac0 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java @@ -1,6 +1,7 @@ // 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.struct.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -31,7 +32,7 @@ private Entry(int outerNameIdx, int simpleNameIdx, int accessFlags, String inner private List entries; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int len = data.readUnsignedShort(); if (len > 0) { entries = new ArrayList<>(len); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java index e641b39da5..f240341ef0 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; import org.jetbrains.java.decompiler.util.InterpreterUtil; @@ -19,7 +20,7 @@ public class StructLineNumberTableAttribute extends StructGeneralAttribute { private int[] myLineInfo = InterpreterUtil.EMPTY_INT_ARRAY; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int len = data.readUnsignedShort() * 2; if (len > 0) { myLineInfo = new int[len]; diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java index dfdec3252f..baea20def6 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java @@ -1,6 +1,7 @@ // 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.struct.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; 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; @@ -27,7 +28,7 @@ public class StructLocalVariableTableAttribute extends StructGeneralAttribute { private Map indexVersion = new HashMap<>(); @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int len = data.readUnsignedShort(); if (len > 0) { localVariables = new ArrayList<>(len); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java index cfdda0f283..d0505d31ce 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -20,8 +21,8 @@ public class StructLocalVariableTypeTableAttribute extends StructGeneralAttribut final StructLocalVariableTableAttribute backingAttribute = new StructLocalVariableTableAttribute(); @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { - backingAttribute.initContent(data, pool); + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { + backingAttribute.initContent(data, pool, version); } public void add(StructLocalVariableTypeTableAttribute attr) { diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructMethodParametersAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructMethodParametersAttribute.java index 08133a9707..3e10a5a23c 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructMethodParametersAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructMethodParametersAttribute.java @@ -3,6 +3,7 @@ */ package org.jetbrains.java.decompiler.struct.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -21,7 +22,7 @@ public class StructMethodParametersAttribute extends StructGeneralAttribute { private List myEntries; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int len = data.readUnsignedByte(); List entries; if (len > 0) { diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructModuleAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructModuleAttribute.java index 9fd6f89ddb..45c78a7b10 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructModuleAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructModuleAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -21,7 +22,7 @@ public class StructModuleAttribute extends StructGeneralAttribute { public List provides; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int moduleNameIndex = data.readUnsignedShort(); this.moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString(); this.moduleFlags = data.readUnsignedShort(); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructPermittedSubclassesAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructPermittedSubclassesAttribute.java index 7556ff4425..1630a88686 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructPermittedSubclassesAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructPermittedSubclassesAttribute.java @@ -1,5 +1,6 @@ package org.jetbrains.java.decompiler.struct.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -24,7 +25,7 @@ public List getClasses() { } @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int count = data.readUnsignedShort(); for (int i = 0; i < count; i++) { classes.add(pool.getPrimitiveConstant(data.readUnsignedShort()).getString()); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructRecordAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructRecordAttribute.java index 24c6152ea9..4d1a483618 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructRecordAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructRecordAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.struct.StructRecordComponent; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; @@ -22,11 +23,11 @@ public class StructRecordAttribute extends StructGeneralAttribute { List components; @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int componentCount = data.readUnsignedShort(); StructRecordComponent[] components = new StructRecordComponent[componentCount]; for (int i = 0; i < componentCount; i++) { - components[i] = StructRecordComponent.create(data, pool); + components[i] = StructRecordComponent.create(data, pool, version); } this.components = Arrays.asList(components); } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructTypeAnnotationAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructTypeAnnotationAttribute.java index a202940d2a..72f656edf4 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructTypeAnnotationAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructTypeAnnotationAttribute.java @@ -1,6 +1,7 @@ // 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.attr; +import org.jetbrains.java.decompiler.code.BytecodeVersion; import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.TypeAnnotation; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; @@ -16,7 +17,7 @@ public class StructTypeAnnotationAttribute extends StructGeneralAttribute { private List annotations = Collections.emptyList(); @Override - public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + public void initContent(DataInputFullStream data, ConstantPool pool, BytecodeVersion version) throws IOException { int len = data.readUnsignedShort(); if (len > 0) { annotations = new ArrayList<>(len); diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index cdae215157..e7b9a7d3c3 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -392,6 +392,8 @@ private void registerDefault() { register(JAVA_8, "TestOverrideIndirect"); // TODO: IdeaNotNullHelper doesn't seem to be doing anything registerRaw(CUSTOM, "TestIdeaNotNull"); + // TODO: Synchronized blocks don't work properly + registerRaw(CUSTOM, "TestHotjava"); } private void registerEntireClassPath() { diff --git a/testData/classes/custom/TestHotjava.class b/testData/classes/custom/TestHotjava.class new file mode 100644 index 0000000000000000000000000000000000000000..15afd5befec27c5ba7bda34707ca204d25706b8c GIT binary patch literal 988 zcmZ`&T~E|N6g|`JvddCFT(T(gjVK>WK`at@1s!3oy1#HdYyLMg}H~W3=j9Ddmt0-$2Wi2 zQ`#6hM=!dOc0W8`@-DKTaqZ1{o7_lkfOBRM=rP;XsZsN0d?e6u1xw#g0-nfIS~(x{ z^|7t6D4ppQw#E_la-g{>a}2f-0D&UU+&pdkJ%vfG1B}Kjp#3Y_%l0>vPM8q5&9%gv z1msv`F;mIlFRUDf3_M5pF)M1v$X8G6CS@`8#lXQbC!^})g+toAm}=-H`2b^qaz?vk zSt!rcs=o}6AW!w|q1z}V)kHF<$s=;dmhEKypyTA$50X3tJ$Z{( 4 +3 <-> 3 +7 <-> 8 +8 <-> 8 +10 <-> 13 +15 <-> 16 +16 <-> 19 +21 <-> 27 +22 <-> 30 +27 <-> 38 +28 <-> 42 +29 <-> 42 +Not mapped: +31 From a3e7145be0912e3946c6fbe84139a5e0f4af7da5 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Wed, 17 Nov 2021 23:39:58 -0500 Subject: [PATCH 29/85] Improve try with resources --- .../modules/decompiler/TryHelper.java | 33 ++-- .../pkg/TestTryWithResourcesCatchJ16.dec | 184 +++++++----------- .../pkg/TestTryWithResourcesCatchJ16.java | 2 +- 3 files changed, 86 insertions(+), 133 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java index d48f56b15a..422544021e 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java @@ -1,16 +1,16 @@ package org.jetbrains.java.decompiler.modules.decompiler; -import org.jetbrains.java.decompiler.code.BytecodeVersion; -import org.jetbrains.java.decompiler.code.CodeConstants; 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.RootStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; import org.jetbrains.java.decompiler.struct.StructClass; +import org.jetbrains.java.decompiler.util.DotExporter; import org.jetbrains.java.decompiler.util.StartEndPair; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; public class TryHelper { @@ -105,24 +105,25 @@ private static boolean mergeTry(CatchStatement stat) { // Get inner block of inner try stat Statement innerBlock = inner.getStats().get(0); - // Replace the inner try statement with the block inside - stat.replaceStatement(inner, innerBlock); - - // replaceStatement ends up doubling the amount of edges on the inner block, we need to remove the ones we've already seen - // TODO: this is an internal bug. The edges need to be manually modified otherwise it creates labels - - Set pairs = new HashSet<>(); - for (StatEdge edge : innerBlock.getAllSuccessorEdges()) { - StartEndPair pair = new StartEndPair(edge.getSource().id, edge.getDestination().id); + // Remove successors as the replaceStatement call will add the appropriate successor + List innerEdges = inner.getAllSuccessorEdges(); + for (StatEdge succ : innerBlock.getAllSuccessorEdges()) { + boolean found = false; + for (StatEdge innerEdge : innerEdges) { + if (succ.getDestination() == innerEdge.getDestination() && succ.getType() == innerEdge.getType()) { + found = true; + break; + } + } - // Remove successors that we've already seen - if (pairs.contains(pair)) { - innerBlock.removeSuccessor(edge); - } else { - pairs.add(pair); + if (found) { + innerBlock.removeSuccessor(succ); } } + // Replace the inner try statement with the block inside + stat.replaceStatement(inner, innerBlock); + return true; } } diff --git a/testData/results/pkg/TestTryWithResourcesCatchJ16.dec b/testData/results/pkg/TestTryWithResourcesCatchJ16.dec index cb4f3917ec..e7fe02d7e1 100644 --- a/testData/results/pkg/TestTryWithResourcesCatchJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesCatchJ16.dec @@ -5,35 +5,20 @@ import java.io.FileNotFoundException; import java.util.Scanner; public class TestTryWithResourcesCatchJ16 { - public void test(File file) { - try (Scanner scanner = new Scanner(file)) {// 9 - scanner.next();// 10 - } catch (FileNotFoundException var7) {// 11 - var7.printStackTrace();// 12 - } - - }// 14 - - public void testFunc(File file) { - try (Scanner scanner = this.create(file)) {// 17 - scanner.next();// 18 - } catch (FileNotFoundException var7) {// 19 - var7.printStackTrace();// 20 - } - - }// 22 - public int test1(File file) { int i = 0;// 25 try { System.out.println(-1);// 28 - try (Scanner scanner = this.create(file)) {// 30 + try ( + Scanner scanner = this.create(file);// 30 + Scanner scanner2 = this.create(file); + ) { scanner.next();// 31 ++i;// 32 } - } catch (Exception var8) {// 34 + } catch (Exception var11) {// 34 System.out.println(1);// 35 } @@ -52,110 +37,77 @@ public class TestTryWithResourcesCatchJ16 { } class 'pkg/TestTryWithResourcesCatchJ16' { - method 'test (Ljava/io/File;)V' { - 4 8 - 8 8 - 9 9 - a 9 - b 9 - c 9 - 2a 10 - 2c 11 - 2f 14 - } - - method 'testFunc (Ljava/io/File;)V' { - 0 17 - 1 17 - 2 17 - 3 17 - 4 17 - 5 17 - 6 18 - 7 18 - 8 18 - 9 18 - 2f 19 - 31 20 - 34 23 - } - method 'test1 (Ljava/io/File;)I' { - 0 26 - 1 26 - 2 29 - 3 29 - 4 29 - 5 29 - 6 29 - 7 29 - 8 29 - 9 31 - a 31 - b 31 - c 31 - d 31 - e 31 - f 32 - 10 32 - 11 32 - 12 32 - 14 33 - 3e 35 - 3f 36 - 40 36 - 41 36 - 42 36 - 43 36 - 46 39 - 47 39 - 4a 40 - 4b 40 - 4c 40 - 4d 40 - 4e 40 - 4f 40 - 50 40 - 54 42 - 55 42 - 56 42 - 57 42 - 58 42 - 5b 45 - 5c 45 + 0 8 + 1 8 + 2 11 + 3 11 + 4 11 + 5 11 + 6 11 + 7 11 + 8 11 + 9 14 + a 14 + b 14 + c 14 + d 14 + e 14 + f 15 + 10 15 + 11 15 + 12 15 + 13 15 + 14 15 + 15 15 + 16 17 + 17 17 + 18 17 + 19 17 + 1b 18 + 6d 20 + 6e 21 + 6f 21 + 70 21 + 71 21 + 72 21 + 75 24 + 76 24 + 79 25 + 7a 25 + 7b 25 + 7c 25 + 7d 25 + 7e 25 + 7f 25 + 83 27 + 84 27 + 85 27 + 86 27 + 87 27 + 8a 30 + 8b 30 } method 'create (Ljava/io/File;)Ljava/util/Scanner;' { - 4 49 - 8 49 + 4 34 + 8 34 } } Lines mapping: -9 <-> 9 -10 <-> 10 -11 <-> 11 -12 <-> 12 -14 <-> 15 -17 <-> 18 -18 <-> 19 -19 <-> 20 -20 <-> 21 -22 <-> 24 -25 <-> 27 -28 <-> 30 -30 <-> 32 -31 <-> 33 -32 <-> 34 -34 <-> 36 -35 <-> 37 -38 <-> 40 -39 <-> 41 -41 <-> 43 -44 <-> 46 -48 <-> 50 +25 <-> 9 +28 <-> 12 +30 <-> 15 +31 <-> 18 +32 <-> 19 +34 <-> 21 +35 <-> 22 +38 <-> 25 +39 <-> 26 +41 <-> 28 +44 <-> 31 +48 <-> 35 Not mapped: -13 -21 33 36 diff --git a/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java b/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java index d24f7765d6..c24456c42f 100644 --- a/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java +++ b/testData/src/java16/pkg/TestTryWithResourcesCatchJ16.java @@ -27,7 +27,7 @@ public int test1(File file) { try { System.out.println(-1); - try (Scanner scanner = create(file)) { + try (Scanner scanner = create(file); Scanner scanner2 = create(file)) { scanner.next(); i++; } From 485b3a96020b4d94397058fbc0ad875b999a01e6 Mon Sep 17 00:00:00 2001 From: Simon Wanner Date: Fri, 19 Nov 2021 10:18:15 +0100 Subject: [PATCH 30/85] Add Javadoc tests --- .../decompiler/DecompilerTestFixture.java | 4 ++-- .../java/decompiler/SingleClassesTest.java | 22 +++++++++++++++++++ .../decompiler/SingleClassesTestBase.java | 8 +++---- testData/results/pkg/TestJavadoc.dec | 17 ++++++++++++++ testData/src/java8/pkg/TestJavadoc.java | 9 ++++++++ 5 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 testData/results/pkg/TestJavadoc.dec create mode 100644 testData/src/java8/pkg/TestJavadoc.java diff --git a/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java b/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java index 5bd79680a6..cf6d95eaeb 100644 --- a/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java +++ b/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java @@ -39,7 +39,7 @@ public DecompilerTestFixture() { testDataDir = testDataDir.toAbsolutePath(); } - public void setUp(String... optionPairs) throws IOException { + public void setUp(Object... optionPairs) throws IOException { assertEquals(0, optionPairs.length % 2); assertTrue(isTestDataDir(testDataDir), "current dir: " + new File("").getAbsolutePath()); @@ -57,7 +57,7 @@ public void setUp(String... optionPairs) throws IOException { options.put(IFernflowerPreferences.LITERALS_AS_IS, "1"); options.put(IFernflowerPreferences.UNIT_TEST_MODE, "1"); for (int i = 0; i < optionPairs.length; i += 2) { - options.put(optionPairs[i], optionPairs[i + 1]); + options.put((String) optionPairs[i], optionPairs[i + 1]); } decompiler = new TestConsoleDecompiler(targetDir.toFile(), options); } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index e7b9a7d3c3..35892720f1 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -1,7 +1,11 @@ // 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; +import net.fabricmc.fernflower.api.IFabricJavadocProvider; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import org.jetbrains.java.decompiler.struct.StructClass; +import org.jetbrains.java.decompiler.struct.StructField; +import org.jetbrains.java.decompiler.struct.StructMethod; import static org.jetbrains.java.decompiler.SingleClassesTestBase.TestDefinition.Version.*; @@ -84,6 +88,24 @@ protected void registerAll() { IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "0", IFernflowerPreferences.EXPERIMENTAL_TRY_LOOP_FIX, "1" ); + registerSet("Javadoc", () -> { + register(JAVA_8, "TestJavadoc"); + }, IFabricJavadocProvider.PROPERTY_NAME, new IFabricJavadocProvider() { + @Override + public String getClassDoc(StructClass structClass) { + return "Class javadoc for '" + structClass.qualifiedName + "'"; + } + + @Override + public String getFieldDoc(StructClass structClass, StructField structField) { + return "Field javadoc for '" + structField.getName() + "'"; + } + + @Override + public String getMethodDoc(StructClass structClass, StructMethod structMethod) { + return "Method javadoc for '" + structMethod.getName() + "'"; + } + }); } private void registerDefault() { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java index 385f1e6cf3..dd80019c2a 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java @@ -47,7 +47,7 @@ protected String[] getDecompilerOptions() { protected abstract void registerAll(); - protected final void registerSet(String name, Runnable initializer, String ...options) { + protected final void registerSet(String name, Runnable initializer, Object ...options) { currentTestSet = new TestSet(name, options); initializer.run(); testSets.add(currentTestSet); @@ -115,10 +115,10 @@ private static List collectClasses(Path classFile) { static class TestSet { public final String name; - public final String[] options; + public final Object[] options; public final List testDefinitions = new ArrayList<>(); - public TestSet(String name, String[] options) { + public TestSet(String name, Object[] options) { this.name = name; this.options = options; } @@ -170,7 +170,7 @@ public Path getReferenceFile() { return SingleClassesTestBase.getReferenceFile(fixture, testClass); } - public void run(String[] options) throws IOException { + public void run(Object[] options) throws IOException { fixture.setUp(options); ConsoleDecompiler decompiler = fixture.getDecompiler(); Path classFile = getClassFile(); diff --git a/testData/results/pkg/TestJavadoc.dec b/testData/results/pkg/TestJavadoc.dec new file mode 100644 index 0000000000..a878d4dbaf --- /dev/null +++ b/testData/results/pkg/TestJavadoc.dec @@ -0,0 +1,17 @@ +package pkg; + +/** + * Class javadoc for 'pkg/TestJavadoc' + */ +public class TestJavadoc { + /** + * Field javadoc for 'field' + */ + public int field; + + /** + * Method javadoc for 'method' + */ + public void method() { + } +} diff --git a/testData/src/java8/pkg/TestJavadoc.java b/testData/src/java8/pkg/TestJavadoc.java new file mode 100644 index 0000000000..d368af33c6 --- /dev/null +++ b/testData/src/java8/pkg/TestJavadoc.java @@ -0,0 +1,9 @@ +package pkg; + +public class TestJavadoc { + public int field; + + public void method() { + + } +} \ No newline at end of file From 96016aff47fbc100ae136452a7a895214b9977e1 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Fri, 19 Nov 2021 23:28:06 -0500 Subject: [PATCH 31/85] Prevent try with resources generation in cases where it does more harm than good --- .../decompiler/TryWithResourcesProcessor.java | 18 ++ .../pkg/TestTryWithResourcesCatchJ16.dec | 184 +++++++++----- .../pkg/TestTryWithResourcesReturnJ16.dec | 226 +++++++++++++++++- .../pkg/TestTryWithResourcesReturnJ16.java | 76 ++++-- 4 files changed, 411 insertions(+), 93 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java index e37cbdc200..ae06c8fc6e 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Iterator; +import java.util.List; /** * Processes try catch statements to turns them into try-with-resources statements wherever possible. @@ -177,6 +178,23 @@ public static boolean makeTryWithResourceJ11(CatchStatement tryStatement) { return false; } + // Prevent processing if we find any weird edges, such as those in PackResourcesAdapterV4 + // TODO: find the root cause of the problem and fix it + List regedges = tryStatement.getSuccessorEdges(StatEdge.TYPE_REGULAR); + if (!regedges.isEmpty()) { + Statement destination = regedges.get(0).getDestination(); + if (destination.type == Statement.TYPE_IF) { + List breaks = destination.getSuccessorEdges(StatEdge.TYPE_BREAK); + + if (!breaks.isEmpty()) { + + if (!tryStatement.getParent().containsStatement(breaks.get(0).closure)) { + return false; + } + } + } + } + // Find basic block that contains the resource assignment for (StatEdge edge : tryStatement.getPredecessorEdges(StatEdge.TYPE_REGULAR)) { // Find predecessors that lead towards the target try statement diff --git a/testData/results/pkg/TestTryWithResourcesCatchJ16.dec b/testData/results/pkg/TestTryWithResourcesCatchJ16.dec index e7fe02d7e1..1e7e3e1ab3 100644 --- a/testData/results/pkg/TestTryWithResourcesCatchJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesCatchJ16.dec @@ -5,6 +5,24 @@ import java.io.FileNotFoundException; import java.util.Scanner; public class TestTryWithResourcesCatchJ16 { + public void test(File file) { + try (Scanner scanner = new Scanner(file)) {// 9 + scanner.next();// 10 + } catch (FileNotFoundException var7) {// 11 + var7.printStackTrace();// 12 + } + + }// 14 + + public void testFunc(File file) { + try (Scanner scanner = this.create(file)) {// 17 + scanner.next();// 18 + } catch (FileNotFoundException var7) {// 19 + var7.printStackTrace();// 20 + } + + }// 22 + public int test1(File file) { int i = 0;// 25 @@ -37,77 +55,117 @@ public class TestTryWithResourcesCatchJ16 { } class 'pkg/TestTryWithResourcesCatchJ16' { + method 'test (Ljava/io/File;)V' { + 4 8 + 8 8 + 9 9 + a 9 + b 9 + c 9 + 2a 10 + 2c 11 + 2f 14 + } + + method 'testFunc (Ljava/io/File;)V' { + 0 17 + 1 17 + 2 17 + 3 17 + 4 17 + 5 17 + 6 18 + 7 18 + 8 18 + 9 18 + 2f 19 + 31 20 + 34 23 + } + method 'test1 (Ljava/io/File;)I' { - 0 8 - 1 8 - 2 11 - 3 11 - 4 11 - 5 11 - 6 11 - 7 11 - 8 11 - 9 14 - a 14 - b 14 - c 14 - d 14 - e 14 - f 15 - 10 15 - 11 15 - 12 15 - 13 15 - 14 15 - 15 15 - 16 17 - 17 17 - 18 17 - 19 17 - 1b 18 - 6d 20 - 6e 21 - 6f 21 - 70 21 - 71 21 - 72 21 - 75 24 - 76 24 - 79 25 - 7a 25 - 7b 25 - 7c 25 - 7d 25 - 7e 25 - 7f 25 - 83 27 - 84 27 - 85 27 - 86 27 - 87 27 - 8a 30 - 8b 30 + 0 26 + 1 26 + 2 29 + 3 29 + 4 29 + 5 29 + 6 29 + 7 29 + 8 29 + 9 32 + a 32 + b 32 + c 32 + d 32 + e 32 + f 33 + 10 33 + 11 33 + 12 33 + 13 33 + 14 33 + 15 33 + 16 35 + 17 35 + 18 35 + 19 35 + 1b 36 + 6d 38 + 6e 39 + 6f 39 + 70 39 + 71 39 + 72 39 + 75 42 + 76 42 + 79 43 + 7a 43 + 7b 43 + 7c 43 + 7d 43 + 7e 43 + 7f 43 + 83 45 + 84 45 + 85 45 + 86 45 + 87 45 + 8a 48 + 8b 48 } method 'create (Ljava/io/File;)Ljava/util/Scanner;' { - 4 34 - 8 34 + 4 52 + 8 52 } } Lines mapping: -25 <-> 9 -28 <-> 12 -30 <-> 15 -31 <-> 18 -32 <-> 19 -34 <-> 21 -35 <-> 22 -38 <-> 25 -39 <-> 26 -41 <-> 28 -44 <-> 31 -48 <-> 35 +9 <-> 9 +10 <-> 10 +11 <-> 11 +12 <-> 12 +14 <-> 15 +17 <-> 18 +18 <-> 19 +19 <-> 20 +20 <-> 21 +22 <-> 24 +25 <-> 27 +28 <-> 30 +30 <-> 33 +31 <-> 36 +32 <-> 37 +34 <-> 39 +35 <-> 40 +38 <-> 43 +39 <-> 44 +41 <-> 46 +44 <-> 49 +48 <-> 53 Not mapped: +13 +21 33 36 diff --git a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec index 0469d94f61..612f36875e 100644 --- a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec @@ -90,8 +90,81 @@ public class TestTryWithResourcesReturnJ16 { // 57: areturn } + public String testComplex(File f, File f2, File f3) throws FileNotFoundException { + Scanner scanner = this.create(f); + + String o; + label104: { + Object var16; + try { + Scanner s2 = this.create(f2);// 43 + + label106: { + try { + scanner.next();// 44 + if (!scanner.hasNext() || !s2.hasNext()) {// 46 + var16 = null; + break label106; + } + + try (Scanner s = this.create(f3)) {// 50 + scanner.next();// 51 + + for(int i = 0; i < s.nextInt(); ++i) {// 53 + System.out.println(i);// 54 + } + + o = s.next();// 57 + } + } catch (Throwable var14) { + if (s2 != null) { + try { + s2.close(); + } catch (Throwable var11) { + var14.addSuppressed(var11); + } + } + + throw var14; + } + + if (s2 != null) { + s2.close(); + } + break label104; + } + + if (s2 != null) { + s2.close(); + } + } catch (Throwable var15) {// 42 + if (scanner != null) { + try { + scanner.close(); + } catch (Throwable var10) { + var15.addSuppressed(var10); + } + } + + throw var15; + } + + if (scanner != null) { + scanner.close(); + } + + return (String)var16;// 47 + } + + if (scanner != null) {// 59 + scanner.close(); + } + + return o;// 61 + } + private Scanner create(File file) throws FileNotFoundException { - return new Scanner(file);// 41 + return new Scanner(file);// 65 } } @@ -125,9 +198,141 @@ class 'pkg/TestTryWithResourcesReturnJ16' { 10 31 } - method 'create (Ljava/io/File;)Ljava/util/Scanner;' { + method 'testComplex (Ljava/io/File;Ljava/io/File;Ljava/io/File;)Ljava/lang/String;' { + 0 93 + 1 93 + 2 93 + 3 93 4 93 - 8 93 + 5 93 + 6 93 + 7 99 + 8 99 + 9 99 + a 99 + b 99 + c 99 + d 99 + e 103 + f 103 + 10 103 + 11 103 + 12 103 + 14 104 + 15 104 + 16 104 + 17 104 + 18 104 + 19 104 + 1c 104 + 1d 104 + 1e 104 + 1f 104 + 20 104 + 21 104 + 24 105 + 25 105 + 26 105 + 27 136 + 28 136 + 29 136 + 2c 137 + 2d 137 + 2e 137 + 31 151 + 32 151 + 33 151 + 36 152 + 37 152 + 38 152 + 3b 155 + 3c 155 + 3d 155 + 3e 109 + 3f 109 + 40 109 + 41 109 + 42 109 + 43 109 + 44 109 + 45 110 + 46 110 + 47 110 + 48 110 + 49 110 + 4b 112 + 4c 112 + 4d 112 + 4e 112 + 4f 112 + 50 112 + 51 112 + 52 112 + 53 112 + 54 112 + 55 112 + 58 113 + 59 113 + 5a 113 + 5b 113 + 5c 113 + 5d 113 + 5e 113 + 5f 113 + 60 112 + 61 112 + 62 112 + 66 116 + 67 116 + 68 116 + 69 116 + 6a 116 + 6b 116 + 6c 116 + 95 130 + 96 130 + 97 130 + 9a 131 + 9b 131 + 9c 131 + 9d 131 + 9e 131 + a2 118 + a4 119 + a5 119 + a6 119 + a9 121 + aa 121 + ab 121 + b1 122 + b7 123 + bc 127 + bd 158 + be 158 + bf 158 + c2 159 + c3 159 + c4 159 + c5 159 + c6 159 + ca 139 + cc 140 + cd 140 + ce 140 + d1 142 + d2 142 + d3 142 + d9 143 + df 144 + e4 148 + e5 162 + e6 162 + e7 162 + } + + method 'create (Ljava/io/File;)Ljava/util/Scanner;' { + 4 166 + 8 166 } } @@ -138,9 +343,22 @@ Lines mapping: 16 <-> 23 21 <-> 28 24 <-> 32 -41 <-> 94 +42 <-> 140 +43 <-> 100 +44 <-> 104 +46 <-> 105 +47 <-> 156 +50 <-> 110 +51 <-> 111 +53 <-> 113 +54 <-> 114 +57 <-> 117 +59 <-> 159 +61 <-> 163 +65 <-> 167 Not mapped: 11 17 22 23 +58 diff --git a/testData/src/java16/pkg/TestTryWithResourcesReturnJ16.java b/testData/src/java16/pkg/TestTryWithResourcesReturnJ16.java index 133124b135..91f5ccd963 100644 --- a/testData/src/java16/pkg/TestTryWithResourcesReturnJ16.java +++ b/testData/src/java16/pkg/TestTryWithResourcesReturnJ16.java @@ -5,39 +5,63 @@ import java.util.Scanner; public class TestTryWithResourcesReturnJ16 { - public Scanner test(File file) throws FileNotFoundException { - try (Scanner scanner = new Scanner(file)) { - return scanner; - } + public Scanner test(File file) throws FileNotFoundException { + try (Scanner scanner = new Scanner(file)) { + return scanner; } + } - public Scanner testFunc(File file) throws FileNotFoundException { - try (Scanner scanner = create(file)) { - return scanner; - } + public Scanner testFunc(File file) throws FileNotFoundException { + try (Scanner scanner = create(file)) { + return scanner; } + } - public Scanner testFinally(File file) { - try (Scanner scanner = new Scanner(file)) { - return scanner; - } finally { - return null; - } + public Scanner testFinally(File file) { + try (Scanner scanner = new Scanner(file)) { + return scanner; + } finally { + return null; } + } - public Scanner testFinallyNested(File file) { - try (Scanner scanner = new Scanner(file)) { - try (Scanner scanner2 = new Scanner(file)) { - return scanner2; - } finally { - return scanner; - } - } finally { - return null; - } + public Scanner testFinallyNested(File file) { + try (Scanner scanner = new Scanner(file)) { + try (Scanner scanner2 = new Scanner(file)) { + return scanner2; + } finally { + return scanner; + } + } finally { + return null; } + } + + public String testComplex(File f, File f2, File f3) throws FileNotFoundException { + String o; + try (Scanner scanner = create(f); + Scanner s2 = create(f2)) { + scanner.next(); + + if (!(scanner.hasNext() && s2.hasNext())) { + return null; + } - private Scanner create(File file) throws FileNotFoundException { - return new Scanner(file); + try (Scanner s = create(f3)) { + scanner.next(); + + for (int i = 0; i < s.nextInt(); i++) { + System.out.println(i); + } + + o = s.next(); + } } + + return o; + } + + private Scanner create(File file) throws FileNotFoundException { + return new Scanner(file); + } } From 17aaad856d7725771cdd21d2800b07757d179973 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sat, 20 Nov 2021 00:42:00 -0500 Subject: [PATCH 32/85] Add labeled breaks test --- .../java/decompiler/SingleClassesTest.java | 1 + testData/results/pkg/TestLabeledBreaks.dec | 200 ++++++++++++++++++ testData/src/java8/pkg/TestLabeledBreaks.java | 60 ++++++ 3 files changed, 261 insertions(+) create mode 100644 testData/results/pkg/TestLabeledBreaks.dec create mode 100644 testData/src/java8/pkg/TestLabeledBreaks.java diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 35892720f1..c586788442 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -416,6 +416,7 @@ private void registerDefault() { registerRaw(CUSTOM, "TestIdeaNotNull"); // TODO: Synchronized blocks don't work properly registerRaw(CUSTOM, "TestHotjava"); + register(JAVA_8, "TestLabeledBreaks"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestLabeledBreaks.dec b/testData/results/pkg/TestLabeledBreaks.dec new file mode 100644 index 0000000000..df792a006d --- /dev/null +++ b/testData/results/pkg/TestLabeledBreaks.dec @@ -0,0 +1,200 @@ +package pkg; + +public class TestLabeledBreaks { + public void test(int a) { + System.out.println("1");// 10 + if (a != 1) {// 11 + System.out.println("2");// 15 + } + + }// 17 + + public void test1(int a) { + int i = 0; + + while(true) { + if (i < a) { + System.out.println("1");// 22 + if (a == 1) {// 23 + break; + } + + if (a != 2) {// 27 + System.out.println("2");// 31 + ++i;// 21 + continue; + } + } + + System.out.println("3");// 34 + break; + } + + System.out.println("4");// 37 + }// 38 + + public void test2(int a) { + for(int i = 0; i < a; ++i) {// 41 + System.out.println("1");// 43 + if (a != 1) {// 44 + if (a == 2) {// 48 + break; + } + + System.out.println("2");// 52 + } + + System.out.println("3");// 55 + } + + System.out.println("4");// 58 + }// 59 +} + +class 'pkg/TestLabeledBreaks' { + method 'test (I)V' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 6 4 + 7 4 + 8 5 + 9 5 + a 5 + 10 6 + 11 6 + 12 6 + 13 6 + 14 6 + 15 6 + 18 9 + } + + method 'test1 (I)V' { + 0 12 + 1 12 + 2 15 + 3 15 + 4 15 + 7 16 + 8 16 + 9 16 + a 16 + b 16 + c 16 + d 16 + e 16 + f 17 + 10 17 + 11 17 + 17 21 + 18 21 + 19 21 + 1f 22 + 20 22 + 21 22 + 22 22 + 23 22 + 24 22 + 25 22 + 26 22 + 27 23 + 28 23 + 29 23 + 2a 24 + 2d 28 + 2e 28 + 2f 28 + 30 28 + 31 28 + 32 28 + 35 32 + 36 32 + 37 32 + 38 32 + 39 32 + 3a 32 + 3b 32 + 3c 32 + 3d 33 + } + + method 'test2 (I)V' { + 0 36 + 1 36 + 2 36 + 3 36 + 4 36 + 7 37 + 8 37 + 9 37 + a 37 + b 37 + c 37 + d 37 + e 37 + f 38 + 10 38 + 11 38 + 17 39 + 18 39 + 19 39 + 1f 43 + 20 43 + 21 43 + 22 43 + 23 43 + 24 43 + 27 46 + 28 46 + 29 46 + 2a 46 + 2b 46 + 2c 46 + 2d 46 + 2e 46 + 2f 36 + 30 36 + 31 36 + 35 49 + 36 49 + 37 49 + 38 49 + 39 49 + 3a 49 + 3b 49 + 3c 49 + 3d 50 + } +} + +Lines mapping: +10 <-> 5 +11 <-> 6 +15 <-> 7 +17 <-> 10 +21 <-> 24 +22 <-> 17 +23 <-> 18 +27 <-> 22 +31 <-> 23 +34 <-> 29 +37 <-> 33 +38 <-> 34 +41 <-> 37 +43 <-> 38 +44 <-> 39 +48 <-> 40 +52 <-> 44 +55 <-> 47 +58 <-> 50 +59 <-> 51 +Not mapped: +12 +24 +28 +45 +49 diff --git a/testData/src/java8/pkg/TestLabeledBreaks.java b/testData/src/java8/pkg/TestLabeledBreaks.java new file mode 100644 index 0000000000..3afa53f674 --- /dev/null +++ b/testData/src/java8/pkg/TestLabeledBreaks.java @@ -0,0 +1,60 @@ +package pkg; + +public class TestLabeledBreaks { + // Mom can get some goto? + // We already have goto at home. + // The goto at home: + + public void test(int a) { + a1: { + System.out.println("1"); + if (a == 1) { + break a1; + } + + System.out.println("2"); + } + } + + public void test1(int a) { + a1: { + for (int i = 0; i < a; i++) { + System.out.println("1"); + if (a == 1) { + break a1; + } + + if (a == 2) { + break; + } + + System.out.println("2"); + } + + System.out.println("3"); + } + + System.out.println("4"); + } + + public void test2(int a) { + for (int i = 0; i < a; i++) { + a1: { + System.out.println("1"); + if (a == 1) { + break a1; + } + + if (a == 2) { + break; + } + + System.out.println("2"); + } + + System.out.println("3"); + } + + System.out.println("4"); + } +} From 3728305862f9c2386315b08ed14c4a1d22c0d72d Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sat, 20 Nov 2021 10:39:49 -0500 Subject: [PATCH 33/85] Rename entities test --- .../decompiler/main/ClassesProcessor.java | 11 +++++++---- .../java/decompiler/SingleClassesTest.java | 10 ++++++++++ testData/results/pkg/TestRenameEntities.dec | 18 ++++++++++++++++++ .../src/java8/pkg/TestRenameEntities.java | 19 +++++++++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 testData/results/pkg/TestRenameEntities.dec create mode 100644 testData/src/java8/pkg/TestRenameEntities.java diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index c995d5928c..c36c59a3e4 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -447,10 +447,13 @@ else if (moduleInfo) { // get the class by name StructClass clazz = DecompilerContext.getStructContext().getClass(classAndMethod.a); StructMethod method = clazz.getMethod(classAndMethod.b); - StructLineNumberTableAttribute lineNumberTable = - method.getAttribute(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); - tracer.setLineNumberTable(lineNumberTable); - DecompilerContext.getBytecodeSourceMapper().addTracer(classAndMethod.a, classAndMethod.b, tracer); + + if (method != null) { + StructLineNumberTableAttribute lineNumberTable = + method.getAttribute(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); + tracer.setLineNumberTable(lineNumberTable); + DecompilerContext.getBytecodeSourceMapper().addTracer(classAndMethod.a, classAndMethod.b, tracer); + } }); int index = cl.qualifiedName.lastIndexOf('/'); diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index c586788442..92d4d26954 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -106,6 +106,16 @@ public String getMethodDoc(StructClass structClass, StructMethod structMethod) { return "Method javadoc for '" + structMethod.getName() + "'"; } }); + registerSet("Renaming", () -> register(JAVA_8, "TestRenameEntities"), + IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", + IFernflowerPreferences.DUMP_ORIGINAL_LINES, "1", + IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR, "0", + IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", + IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", + IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "0", + IFernflowerPreferences.RENAME_ENTITIES, "1" + ); + // TODO: user renamer class test } private void registerDefault() { diff --git a/testData/results/pkg/TestRenameEntities.dec b/testData/results/pkg/TestRenameEntities.dec new file mode 100644 index 0000000000..e1a7522644 --- /dev/null +++ b/testData/results/pkg/TestRenameEntities.dec @@ -0,0 +1,18 @@ +package pkg; + +public class TestRenameEntities { + public class class_1 { + public Object a; + + public void a() { + } + } + + public class class_0 { + public Object a; + + public void a() { + } + } +} + diff --git a/testData/src/java8/pkg/TestRenameEntities.java b/testData/src/java8/pkg/TestRenameEntities.java new file mode 100644 index 0000000000..3727aa1874 --- /dev/null +++ b/testData/src/java8/pkg/TestRenameEntities.java @@ -0,0 +1,19 @@ +package pkg; + +public class TestRenameEntities { + public class a { + public Object a; + + public void a() { + + } + } + + public class b { + public Object a; + + public void a() { + + } + } +} From b8117f10cdf2230a8c9efb53c9e8749e187e6f33 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sun, 21 Nov 2021 00:46:44 -0500 Subject: [PATCH 34/85] Add more tests, fix NPE in J8 try with resources --- .../decompiler/TryWithResourcesProcessor.java | 2 +- .../java/decompiler/SingleClassesTest.java | 10 +- testData/results/pkg/TestLoopFinally.dec | 239 +++++ testData/results/pkg/TestSwitchFinally.dec | 514 ++++++++++ testData/results/pkg/TestSwitchLoop.dec | 969 ++++++++++++++++++ .../pkg/TestTryWithResourcesLoopJ16.dec | 627 ++++++++++++ .../pkg/TestTryWithResourcesReturnJ16.dec | 273 ++++- .../pkg/TestTryWithResourcesSwitchJ16.dec | 385 +++++++ .../pkg/TestTryWithResourcesLoopJ16.java | 76 ++ .../pkg/TestTryWithResourcesReturnJ16.java | 25 + .../pkg/TestTryWithResourcesSwitchJ16.java | 73 ++ testData/src/java8/pkg/TestLoopFinally.java | 61 ++ testData/src/java8/pkg/TestSwitchFinally.java | 83 ++ testData/src/java8/pkg/TestSwitchLoop.java | 248 +++++ 14 files changed, 3579 insertions(+), 6 deletions(-) create mode 100644 testData/results/pkg/TestLoopFinally.dec create mode 100644 testData/results/pkg/TestSwitchFinally.dec create mode 100644 testData/results/pkg/TestSwitchLoop.dec create mode 100644 testData/results/pkg/TestTryWithResourcesLoopJ16.dec create mode 100644 testData/results/pkg/TestTryWithResourcesSwitchJ16.dec create mode 100644 testData/src/java16/pkg/TestTryWithResourcesLoopJ16.java create mode 100644 testData/src/java16/pkg/TestTryWithResourcesSwitchJ16.java create mode 100644 testData/src/java8/pkg/TestLoopFinally.java create mode 100644 testData/src/java8/pkg/TestSwitchFinally.java create mode 100644 testData/src/java8/pkg/TestSwitchLoop.java diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java index ae06c8fc6e..dbeda35b5c 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java @@ -26,7 +26,7 @@ public static boolean makeTryWithResource(CatchAllStatement finallyStat) { } Statement toCheck = finallyStat.getHandler().getFirst(); - if (toCheck.type != Statement.TYPE_IF || ((IfStatement)toCheck).getIfstat().type != Statement.TYPE_IF) { + if (toCheck.type != Statement.TYPE_IF || ((IfStatement)toCheck).getIfstat() == null || ((IfStatement)toCheck).getIfstat().type != Statement.TYPE_IF) { return false; } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 92d4d26954..2d22690e53 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -427,6 +427,13 @@ private void registerDefault() { // TODO: Synchronized blocks don't work properly registerRaw(CUSTOM, "TestHotjava"); register(JAVA_8, "TestLabeledBreaks"); + register(JAVA_8, "TestSwitchLoop"); + // TODO: finally block is duplicating the switches, FinallyProcessor#verifyFinallyEx not correct + register(JAVA_8, "TestSwitchFinally"); + // TODO: test2- continue not explicit, causes improper control flow + // TODO: test6&7- for loop processing leaves empty switch default edge + // TODO: test9&10- for loop not created, loop extractor needs another pass + register(JAVA_8, "TestLoopFinally"); } private void registerEntireClassPath() { @@ -469,8 +476,9 @@ private void registerJavaRuntime() { register(JAVA_16, "TestTryWithResourcesNullJ16"); // TODO: doesn't make try with resources block register(JAVA_16, "TestTryWithResourcesOuterJ16"); - // TODO: fails to decompile + register(JAVA_16, "TestTryWithResourcesLoopJ16"); register(JAVA_16, "TestTryWithResourcesFake"); + register(JAVA_16, "TestTryWithResourcesSwitchJ16"); } private void registerLiterals() { diff --git a/testData/results/pkg/TestLoopFinally.dec b/testData/results/pkg/TestLoopFinally.dec new file mode 100644 index 0000000000..cdbe8197aa --- /dev/null +++ b/testData/results/pkg/TestLoopFinally.dec @@ -0,0 +1,239 @@ +package pkg; + +public class TestLoopFinally { + public void test() { + for(int i = 0; i < 10; ++i) {// 5 16 + try { + System.out.println(i);// 7 + } finally { + System.out.println("finally");// 9 + if (i == 5) {// 11 + break; + } + + System.out.println("finally2");// 15 + } + } + + System.out.println("after");// 19 + }// 20 + + public void test1() { + for(int i = 0; i < 10; ++i) {// 23 + try { + System.out.println(i);// 25 + } finally { + System.out.println("finally");// 27 + if (i != 5) {// 29 + if (i == 4) {// 32 + System.out.println("break");// 33 + break;// 34 + } + + System.out.println("finally2");// 37 + } + + System.out.println("continue");// 30 + continue;// 31 + } + } + + System.out.println("after");// 41 + }// 42 + + public void test2() { + for(int i = 0; i < 10; ++i) {// 45 + try { + System.out.println(i);// 47 + } finally { + System.out.println("finally");// 49 + if (i != 5) {// 51 + ; + } + break; + } + } + + System.out.println("after");// 59 + }// 60 +} + +class 'pkg/TestLoopFinally' { + method 'test ()V' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 8 6 + 9 6 + a 6 + b 6 + c 6 + 27 4 + 2a 8 + 2b 8 + 2c 8 + 2d 8 + 2e 8 + 2f 8 + 30 9 + 31 9 + 32 9 + 33 9 + 34 9 + 3b 13 + 3c 13 + 3d 13 + 3e 13 + 3f 13 + 40 13 + 41 13 + 42 13 + 4b 17 + 4c 17 + 4d 17 + 4e 17 + 4f 17 + 50 17 + 51 17 + 52 17 + 53 18 + } + + method 'test1 ()V' { + 0 21 + 1 21 + 2 21 + 3 21 + 4 21 + 5 21 + 8 23 + 9 23 + a 23 + b 23 + c 23 + 42 25 + 43 25 + 44 25 + 45 25 + 46 25 + 47 25 + 48 26 + 49 26 + 4a 26 + 4b 26 + 4c 26 + 50 35 + 51 35 + 52 35 + 53 35 + 54 35 + 55 35 + 56 35 + 57 35 + 58 36 + 5b 27 + 5c 27 + 5d 27 + 60 28 + 61 28 + 62 28 + 63 28 + 64 28 + 65 28 + 66 28 + 67 28 + 68 29 + 6b 32 + 6c 32 + 6d 32 + 6e 32 + 6f 32 + 70 32 + 71 32 + 72 32 + 75 21 + 76 21 + 77 21 + 7b 40 + 7c 40 + 7d 40 + 7e 40 + 7f 40 + 80 40 + 81 40 + 82 40 + 83 41 + } + + method 'test2 ()V' { + 0 44 + 1 44 + 2 44 + 3 44 + 4 44 + 5 44 + 8 46 + 9 46 + a 46 + b 46 + c 46 + 1f 48 + 20 48 + 21 48 + 22 48 + 23 48 + 24 48 + 25 49 + 26 49 + 27 49 + 28 49 + 29 49 + 30 44 + 31 44 + 32 44 + 36 56 + 37 56 + 38 56 + 39 56 + 3a 56 + 3b 56 + 3c 56 + 3d 56 + 3e 57 + } +} + +Lines mapping: +5 <-> 5 +7 <-> 7 +9 <-> 9 +11 <-> 10 +15 <-> 14 +16 <-> 5 +19 <-> 18 +20 <-> 19 +23 <-> 22 +25 <-> 24 +27 <-> 26 +29 <-> 27 +30 <-> 36 +31 <-> 37 +32 <-> 28 +33 <-> 29 +34 <-> 30 +37 <-> 33 +41 <-> 41 +42 <-> 42 +45 <-> 45 +47 <-> 47 +49 <-> 49 +51 <-> 50 +59 <-> 57 +60 <-> 58 +Not mapped: +12 +38 +52 diff --git a/testData/results/pkg/TestSwitchFinally.dec b/testData/results/pkg/TestSwitchFinally.dec new file mode 100644 index 0000000000..f0c09b3ab0 --- /dev/null +++ b/testData/results/pkg/TestSwitchFinally.dec @@ -0,0 +1,514 @@ +package pkg; + +public class TestSwitchFinally { + public void test(int i) { + boolean var4 = false; + + try { + var4 = true;// 6 + System.out.println(1); + var4 = false; + } finally { + if (var4) { + System.out.println("finally");// 8 + switch(i) {// 10 + case 0: + System.out.println("0");// 12 + } + + System.out.println("b");// 16 + } + } + + System.out.println("finally"); + switch(i) { + case 0: + System.out.println("0"); + default: + System.out.println("b"); + } + }// 17 + + public void test1(int i) { + try { + System.out.println(1);// 22 + } finally { + System.out.println("finally");// 24 + switch(i) {// 26 + case 0: + System.out.println("0");// 28 + break;// 29 + case 1: + System.out.println("1");// 31 + } + + System.out.println("b");// 35 + } + + }// 36 + + public void test2(int i) { + boolean var4 = false; + + try { + var4 = true;// 41 + System.out.println(1); + var4 = false; + } finally { + if (var4) { + System.out.println("finally");// 43 + switch(i) {// 45 + default: + System.out.println("default");// 47 + System.out.println("b");// 50 + } + } + } + + System.out.println("finally"); + switch(i) { + default: + System.out.println("default"); + System.out.println("b"); + } + }// 51 + + public int test3(int i) { + boolean var4 = false; + + label54: { + label53: { + try { + var4 = true;// 57 + System.out.println(1); + var4 = false; + } finally { + if (var4) { + System.out.println("finally");// 59 + switch(i) {// 61 + case 0: + System.out.println("0");// 63 + break;// 64 + case 1: + System.out.println("1");// 66 + break label53;// 67 + default: + System.out.println("Default");// 69 + } + + System.out.println("b");// 72 + } + } + + System.out.println("finally"); + switch(i) { + case 0: + System.out.println("0"); + break label54; + case 1: + System.out.println("1"); + break; + default: + System.out.println("Default"); + break label54; + } + } + + System.out.println("c");// 80 + return 0;// 81 + } + + System.out.println("b"); + System.out.println("d");// 74 76 + return 1;// 77 + } +} + +class 'pkg/TestSwitchFinally' { + method 'test (I)V' { + 0 7 + 1 7 + 2 7 + 3 7 + 4 7 + 7 22 + 8 22 + 9 22 + a 22 + b 22 + c 22 + d 22 + e 22 + f 23 + 10 23 + 24 25 + 25 25 + 26 25 + 27 25 + 28 25 + 29 25 + 2c 27 + 2d 27 + 2e 27 + 2f 27 + 30 27 + 31 27 + 32 27 + 33 27 + 34 29 + 35 29 + 36 29 + 37 12 + 38 12 + 39 12 + 3a 12 + 3b 12 + 3c 12 + 3d 13 + 3e 13 + 3f 13 + 40 13 + 41 29 + 42 29 + 43 29 + 44 29 + 45 29 + 46 29 + 47 29 + 48 29 + 49 29 + 4a 29 + 4b 29 + 4c 29 + 4d 29 + 4e 29 + 4f 29 + 50 29 + 51 29 + 52 29 + 53 29 + 54 15 + 55 15 + 56 15 + 57 15 + 58 15 + 59 15 + 5a 29 + 5b 29 + 5c 18 + 5d 18 + 5e 18 + 5f 18 + 60 18 + 61 18 + 62 18 + 63 18 + 64 29 + 65 29 + } + + method 'test1 (I)V' { + 0 33 + 1 33 + 2 33 + 3 33 + 4 33 + 47 47 + 4a 35 + 4b 35 + 4c 35 + 4d 35 + 4e 35 + 4f 35 + 50 36 + 51 36 + 52 36 + 53 36 + 70 38 + 71 38 + 72 38 + 73 38 + 74 38 + 75 38 + 76 38 + 77 38 + 78 39 + 7b 41 + 7c 41 + 7d 41 + 7e 41 + 7f 41 + 80 41 + 83 44 + 84 44 + 85 44 + 86 44 + 87 44 + 88 44 + 89 44 + 8a 44 + } + + method 'test2 (I)V' { + 0 53 + 1 53 + 2 53 + 3 53 + 4 53 + 7 67 + 8 67 + 9 67 + a 67 + b 67 + c 67 + d 67 + e 67 + f 68 + 10 68 + 1c 70 + 1d 70 + 1e 70 + 1f 70 + 20 70 + 21 70 + 22 70 + 23 70 + 24 71 + 25 71 + 26 71 + 27 71 + 28 71 + 29 71 + 2a 71 + 2b 71 + 2c 73 + 2d 73 + 2e 73 + 2f 58 + 30 58 + 31 58 + 32 58 + 33 58 + 34 58 + 35 59 + 36 59 + 37 59 + 38 59 + 39 73 + 3a 73 + 3b 73 + 3c 73 + 3d 73 + 3e 73 + 3f 73 + 40 73 + 41 73 + 42 73 + 43 73 + 44 61 + 45 61 + 46 61 + 47 61 + 48 61 + 49 61 + 4a 61 + 4b 61 + 4c 62 + 4d 62 + 4e 62 + 4f 62 + 50 62 + 51 62 + 52 62 + 53 62 + 54 73 + 55 73 + } + + method 'test3 (I)I' { + 0 81 + 1 81 + 2 81 + 3 81 + 4 81 + 7 102 + 8 102 + 9 102 + a 102 + b 102 + c 102 + d 102 + e 102 + f 103 + 10 103 + 2c 105 + 2d 105 + 2e 105 + 2f 105 + 30 105 + 31 105 + 32 105 + 33 105 + 34 106 + 37 108 + 38 108 + 39 108 + 3a 108 + 3b 108 + 3c 108 + 3d 108 + 3e 108 + 3f 109 + 42 111 + 43 111 + 44 111 + 45 111 + 46 111 + 47 111 + 4a 120 + 4b 120 + 4c 120 + 4d 120 + 4e 120 + 4f 120 + 50 120 + 51 120 + 52 121 + 53 121 + 54 121 + 55 86 + 56 86 + 57 86 + 58 86 + 59 86 + 5a 86 + 5b 87 + 5c 87 + 5d 87 + 5e 87 + 5f 121 + 60 121 + 61 121 + 62 121 + 63 121 + 64 121 + 65 121 + 66 121 + 67 121 + 68 121 + 69 121 + 6a 121 + 6b 121 + 6c 121 + 6d 121 + 6e 121 + 6f 121 + 70 121 + 71 121 + 72 121 + 73 121 + 74 121 + 75 121 + 76 121 + 77 121 + 78 89 + 79 89 + 7a 89 + 7b 89 + 7c 89 + 7d 89 + 7e 89 + 7f 89 + 80 90 + 81 121 + 82 121 + 83 92 + 84 92 + 85 92 + 86 92 + 87 92 + 88 92 + 89 92 + 8a 92 + 8b 93 + 8c 121 + 8d 121 + 8e 95 + 8f 95 + 90 95 + 91 95 + 92 95 + 93 95 + 94 121 + 95 121 + 96 98 + 97 98 + 98 98 + 99 98 + 9a 98 + 9b 98 + 9c 98 + 9d 98 + 9e 121 + 9f 121 + a0 121 + a1 121 + a2 121 + a3 121 + a4 121 + a5 122 + a6 122 + a7 122 + a8 122 + aa 116 + ab 116 + ac 116 + ad 116 + ae 116 + af 116 + b0 116 + b1 116 + b2 117 + b3 117 + } +} + +Lines mapping: +6 <-> 8 +8 <-> 13 +10 <-> 14 +12 <-> 16 +16 <-> 19 +17 <-> 30 +22 <-> 34 +24 <-> 36 +26 <-> 37 +28 <-> 39 +29 <-> 40 +31 <-> 42 +35 <-> 45 +36 <-> 48 +41 <-> 54 +43 <-> 59 +45 <-> 60 +47 <-> 62 +50 <-> 63 +51 <-> 74 +57 <-> 82 +59 <-> 87 +61 <-> 88 +63 <-> 90 +64 <-> 91 +66 <-> 93 +67 <-> 94 +69 <-> 96 +72 <-> 99 +74 <-> 122 +76 <-> 122 +77 <-> 123 +80 <-> 117 +81 <-> 118 +Not mapped: +18 +37 +52 diff --git a/testData/results/pkg/TestSwitchLoop.dec b/testData/results/pkg/TestSwitchLoop.dec new file mode 100644 index 0000000000..b9b70eae4e --- /dev/null +++ b/testData/results/pkg/TestSwitchLoop.dec @@ -0,0 +1,969 @@ +package pkg; + +public class TestSwitchLoop { + public void test(int i) { + while(i > 0) {// 5 + --i;// 6 + switch(i) {// 8 + case 0: + System.out.println("0");// 10 + break;// 11 + case 1: + System.out.println("1");// 13 + break;// 14 + case 2: + System.out.println("2");// 16 + break;// 17 + default: + System.out.println("after");// 20 + if (i == 4) {// 21 + return;// 25 + } + } + } + + } + + public int test2(int i) { + for(int a = 0; i > a; ++a) {// 29 + --i;// 30 + switch(i) {// 32 + case 0: + System.out.println("0");// 34 + default: + System.out.println("after");// 50 + break; + case 1: + System.out.println("1");// 37 + return 1;// 38 + case 2: + System.out.println("2");// 40 + return 2;// 41 + case 3: + System.out.println("3");// 43 + return 0;// 53 + case 4: + System.out.println("4");// 46 + return 0; + } + } + + return 0; + } + + public int test3(int i) { + label18: + for(int a = 0; i > a; ++a) {// 58 + --i;// 59 + switch(i) {// 61 + case 0: + System.out.println("0");// 63 + default: + System.out.println("after");// 79 + break; + case 1: + System.out.println("1");// 66 + return 1;// 67 + case 2: + System.out.println("2");// 69 + return 2;// 70 + case 3: + System.out.println("3");// 72 + break label18;// 73 + case 4: + System.out.println("4");// 75 + break label18;// 76 + } + } + + System.out.println("after2");// 82 + return 0;// 84 + } + + public void test4(int i) { + for(int a = 0; i > a; ++a) {// 88 + --i;// 89 + switch(i) {// 91 + case 0: + System.out.println("0");// 93 + if (a == 0) {// 94 + continue; + } + break; + case 1: + System.out.println("1");// 100 + } + + System.out.println("after");// 103 + } + + System.out.println("after2");// 106 + }// 107 + + public void test5(int i) { + int a = 0; + + while(true) { + label42: { + if (i > a) { + --i;// 112 + label22: + switch(i) {// 114 + case 0: + System.out.println("0");// 116 + int i1 = 0; + + while(true) { + if (i1 >= 5) { + break label42; + } + + switch(i1) {// 118 + case 0: + System.out.println(0);// 120 + default: + ++i1;// 117 + break; + case 1: + System.out.println(1);// 123 + break label22;// 124 + case 2: + return;// 126 + } + } + case 1: + System.out.println("1");// 132 + default: + break label42; + } + } + + System.out.println("after2");// 138 + return;// 139 + } + + System.out.println("after");// 135 + ++a;// 111 + } + } + + public void test6() { + int i = 0; + + label24: + while(i < 10) { + switch(i) {// 145 + case 0: + System.out.println("0");// 147 + + for(int i1 = 0; i1 < 5; ++i1) {// 148 + switch(i1) {// 149 + case 1: + System.out.println(1);// 151 + break label24;// 152 + default: + } + } + default: + System.out.println("after");// 159 + ++i;// 143 + } + } + + System.out.println("after2");// 162 + }// 163 + + public void test7() { + label21: + for(int i = 0; i < 10; ++i) {// 167 + for(int i1 = 0; i1 < 5; ++i1) {// 168 + switch(i1) {// 169 + case 1: + System.out.println(1);// 171 + break label21;// 172 + default: + } + } + + System.out.println("after");// 176 + } + + System.out.println("after2");// 179 + }// 180 + + public void test8(int i) { + switch(i) {// 183 + case 0: + int j = 0; + + while(true) { + if (j >= 10) { + System.out.println(0);// 192 + break; + } + + if (j == 3) {// 187 + break; + } + + ++j;// 186 + } + + System.out.println("after");// 194 + case 1: + System.out.println(1);// 196 + } + + System.out.println("after2");// 199 + }// 200 + + public void test9(int i) { + label23: + switch(i) {// 203 + case 0: + int j = 0; + + while(true) { + if (j >= 10) { + System.out.println(0);// 212 + break label23;// 213 + } + + if (j == 3) {// 207 + System.out.println("after");// 215 + break; + } + + ++j;// 206 + } + case 1: + System.out.println(1);// 217 + } + + System.out.println("after2");// 220 + }// 221 + + public void test10(int i) { + label33: { + label32: { + switch(i) {// 224 + case 0: + int j = 0; + + while(true) { + if (j >= 10) { + break label32; + } + + if (j == 3) {// 228 + System.out.println("after");// 241 + break; + } + + if (j == 9) {// 232 + break label32; + } + + ++j;// 227 + } + case 1: + break; + default: + break label33; + } + + System.out.println(1);// 243 + break label33; + } + + System.out.println(0);// 237 + } + + System.out.println("after2");// 246 + }// 247 +} + +class 'pkg/TestSwitchLoop' { + method 'test (I)V' { + 0 4 + 1 4 + 4 5 + 5 5 + 6 5 + 7 6 + 8 6 + 24 8 + 25 8 + 26 8 + 27 8 + 28 8 + 29 8 + 2a 8 + 2b 8 + 2c 9 + 2f 11 + 30 11 + 31 11 + 32 11 + 33 11 + 34 11 + 35 11 + 36 11 + 37 12 + 3a 14 + 3b 14 + 3c 14 + 3d 14 + 3e 14 + 3f 14 + 40 14 + 41 14 + 42 15 + 45 17 + 46 17 + 47 17 + 48 17 + 49 17 + 4a 17 + 4b 17 + 4c 17 + 4d 18 + 4e 18 + 4f 18 + 55 19 + } + + method 'test2 (I)I' { + 0 27 + 1 27 + 2 27 + 3 27 + 4 27 + 7 28 + 8 28 + 9 28 + a 29 + b 29 + 2c 31 + 2d 31 + 2e 31 + 2f 31 + 30 31 + 31 31 + 32 31 + 33 31 + 37 36 + 38 36 + 39 36 + 3a 36 + 3b 36 + 3c 36 + 3d 36 + 3e 36 + 3f 37 + 40 37 + 41 39 + 42 39 + 43 39 + 44 39 + 45 39 + 46 39 + 47 39 + 48 39 + 49 40 + 4a 40 + 4b 42 + 4c 42 + 4d 42 + 4e 42 + 4f 42 + 50 42 + 51 42 + 52 42 + 56 45 + 57 45 + 58 45 + 59 45 + 5a 45 + 5b 45 + 5c 45 + 5d 45 + 61 33 + 62 33 + 63 33 + 64 33 + 65 33 + 66 33 + 67 33 + 68 33 + 69 27 + 6a 27 + 6b 27 + 6c 34 + 6f 43 + 70 43 + } + + method 'test3 (I)I' { + 0 55 + 1 55 + 2 55 + 3 55 + 4 55 + 7 56 + 8 56 + 9 56 + a 57 + b 57 + 2c 59 + 2d 59 + 2e 59 + 2f 59 + 30 59 + 31 59 + 32 59 + 33 59 + 37 64 + 38 64 + 39 64 + 3a 64 + 3b 64 + 3c 64 + 3d 64 + 3e 64 + 3f 65 + 40 65 + 41 67 + 42 67 + 43 67 + 44 67 + 45 67 + 46 67 + 47 67 + 48 67 + 49 68 + 4a 68 + 4b 70 + 4c 70 + 4d 70 + 4e 70 + 4f 70 + 50 70 + 51 70 + 52 70 + 53 71 + 56 73 + 57 73 + 58 73 + 59 73 + 5a 73 + 5b 73 + 5c 73 + 5d 73 + 5e 74 + 61 61 + 62 61 + 63 61 + 64 61 + 65 61 + 66 61 + 67 61 + 68 61 + 69 55 + 6a 55 + 6b 55 + 6c 62 + 6f 78 + 70 78 + 71 78 + 72 78 + 73 78 + 74 78 + 75 78 + 76 78 + 77 79 + 78 79 + } + + method 'test4 (I)V' { + 0 83 + 1 83 + 2 83 + 3 83 + 4 83 + 7 84 + 8 84 + 9 84 + a 85 + b 85 + 24 87 + 25 87 + 26 87 + 27 87 + 28 87 + 29 87 + 2a 87 + 2b 87 + 2c 88 + 2d 88 + 33 93 + 34 93 + 35 93 + 36 93 + 37 93 + 38 93 + 3b 96 + 3c 96 + 3d 96 + 3e 96 + 3f 96 + 40 96 + 43 83 + 44 83 + 45 83 + 49 99 + 4a 99 + 4b 99 + 4c 99 + 4d 99 + 4e 99 + 4f 99 + 50 99 + 51 100 + } + + method 'test5 (I)V' { + 0 103 + 1 103 + 2 107 + 3 107 + 4 107 + 7 108 + 8 108 + 9 108 + a 110 + b 110 + 24 112 + 25 112 + 26 112 + 27 112 + 28 112 + 29 112 + 2a 112 + 2b 112 + 2c 113 + 2d 113 + 2e 116 + 2f 116 + 30 116 + 33 120 + 34 120 + 50 122 + 51 122 + 52 122 + 53 122 + 54 122 + 55 122 + 56 122 + 5a 127 + 5b 127 + 5c 127 + 5d 127 + 5e 127 + 5f 127 + 60 127 + 61 128 + 64 130 + 65 124 + 66 124 + 67 124 + 68 125 + 6e 134 + 6f 134 + 70 134 + 71 134 + 72 134 + 73 134 + 76 144 + 77 144 + 78 144 + 79 144 + 7a 144 + 7b 144 + 7c 144 + 7d 144 + 7e 145 + 7f 145 + 80 145 + 84 140 + 85 140 + 86 140 + 87 140 + 88 140 + 89 140 + 8a 140 + 8b 140 + 8c 141 + } + + method 'test6 ()V' { + 0 150 + 1 150 + 2 153 + 3 153 + 4 153 + 5 153 + 8 154 + 9 154 + 1c 156 + 1d 156 + 1e 156 + 1f 156 + 20 156 + 21 156 + 22 156 + 23 156 + 24 158 + 25 158 + 26 158 + 27 158 + 28 158 + 2b 159 + 2c 159 + 40 161 + 41 161 + 42 161 + 43 161 + 44 161 + 45 161 + 46 161 + 47 162 + 4a 158 + 4b 158 + 4c 158 + 50 167 + 51 167 + 52 167 + 53 167 + 54 167 + 55 167 + 56 167 + 57 167 + 58 168 + 59 168 + 5a 168 + 5e 172 + 5f 172 + 60 172 + 61 172 + 62 172 + 63 172 + 64 172 + 65 172 + 66 173 + } + + method 'test7 ()V' { + 0 177 + 1 177 + 2 177 + 3 177 + 4 177 + 5 177 + 8 178 + 9 178 + a 178 + b 178 + c 178 + f 179 + 10 179 + 24 181 + 25 181 + 26 181 + 27 181 + 28 181 + 29 181 + 2a 181 + 2b 182 + 2e 178 + 2f 178 + 30 178 + 34 187 + 35 187 + 36 187 + 37 187 + 38 187 + 39 187 + 3a 187 + 3b 187 + 3c 177 + 3d 177 + 3e 177 + 42 190 + 43 190 + 44 190 + 45 190 + 46 190 + 47 190 + 48 190 + 49 190 + 4a 191 + } + + method 'test8 (I)V' { + 0 194 + 1 194 + 1c 196 + 1d 196 + 1e 199 + 1f 199 + 20 199 + 21 199 + 24 204 + 25 204 + 26 204 + 2c 208 + 2d 208 + 2e 208 + 32 200 + 33 200 + 34 200 + 35 200 + 36 200 + 39 211 + 3a 211 + 3b 211 + 3c 211 + 3d 211 + 3e 211 + 41 213 + 42 213 + 43 213 + 44 213 + 45 213 + 48 216 + 49 216 + 4a 216 + 4b 216 + 4c 216 + 4d 216 + 4e 216 + 4f 216 + 50 217 + } + + method 'test9 (I)V' { + 0 221 + 1 221 + 1c 223 + 1d 223 + 1e 226 + 1f 226 + 20 226 + 21 226 + 24 231 + 25 231 + 26 231 + 2c 236 + 2d 236 + 2e 236 + 32 227 + 33 227 + 34 227 + 35 227 + 36 227 + 37 227 + 38 227 + 39 228 + 3c 232 + 3d 232 + 3e 232 + 3f 232 + 40 232 + 41 232 + 44 239 + 45 239 + 46 239 + 47 239 + 48 239 + 4b 242 + 4c 242 + 4d 242 + 4e 242 + 4f 242 + 50 242 + 51 242 + 52 242 + 53 243 + } + + method 'test10 (I)V' { + 0 248 + 1 248 + 1c 250 + 1d 250 + 1e 253 + 1f 253 + 20 253 + 21 253 + 24 257 + 25 257 + 26 257 + 2c 262 + 2d 262 + 2e 262 + 2f 262 + 35 266 + 36 266 + 37 266 + 3b 278 + 3c 278 + 3d 278 + 3e 278 + 3f 278 + 40 278 + 41 278 + 45 258 + 46 258 + 47 258 + 48 258 + 49 258 + 4a 258 + 4d 274 + 4e 274 + 4f 274 + 50 274 + 51 274 + 54 281 + 55 281 + 56 281 + 57 281 + 58 281 + 59 281 + 5a 281 + 5b 281 + 5c 282 + } +} + +Lines mapping: +5 <-> 5 +6 <-> 6 +8 <-> 7 +10 <-> 9 +11 <-> 10 +13 <-> 12 +14 <-> 13 +16 <-> 15 +17 <-> 16 +20 <-> 18 +21 <-> 19 +25 <-> 20 +29 <-> 28 +30 <-> 29 +32 <-> 30 +34 <-> 32 +37 <-> 37 +38 <-> 38 +40 <-> 40 +41 <-> 41 +43 <-> 43 +46 <-> 46 +50 <-> 34 +53 <-> 44 +58 <-> 56 +59 <-> 57 +61 <-> 58 +63 <-> 60 +66 <-> 65 +67 <-> 66 +69 <-> 68 +70 <-> 69 +72 <-> 71 +73 <-> 72 +75 <-> 74 +76 <-> 75 +79 <-> 62 +82 <-> 79 +84 <-> 80 +88 <-> 84 +89 <-> 85 +91 <-> 86 +93 <-> 88 +94 <-> 89 +100 <-> 94 +103 <-> 97 +106 <-> 100 +107 <-> 101 +111 <-> 146 +112 <-> 109 +114 <-> 111 +116 <-> 113 +117 <-> 125 +118 <-> 121 +120 <-> 123 +123 <-> 128 +124 <-> 129 +126 <-> 131 +132 <-> 135 +135 <-> 145 +138 <-> 141 +139 <-> 142 +143 <-> 169 +145 <-> 155 +147 <-> 157 +148 <-> 159 +149 <-> 160 +151 <-> 162 +152 <-> 163 +159 <-> 168 +162 <-> 173 +163 <-> 174 +167 <-> 178 +168 <-> 179 +169 <-> 180 +171 <-> 182 +172 <-> 183 +176 <-> 188 +179 <-> 191 +180 <-> 192 +183 <-> 195 +186 <-> 209 +187 <-> 205 +192 <-> 201 +194 <-> 212 +196 <-> 214 +199 <-> 217 +200 <-> 218 +203 <-> 222 +206 <-> 237 +207 <-> 232 +212 <-> 228 +213 <-> 229 +215 <-> 233 +217 <-> 240 +220 <-> 243 +221 <-> 244 +224 <-> 249 +227 <-> 267 +228 <-> 258 +232 <-> 263 +237 <-> 279 +241 <-> 259 +243 <-> 275 +246 <-> 282 +247 <-> 283 +Not mapped: +22 +35 +44 +47 +64 +95 +121 +130 +188 +208 +229 +233 +238 diff --git a/testData/results/pkg/TestTryWithResourcesLoopJ16.dec b/testData/results/pkg/TestTryWithResourcesLoopJ16.dec new file mode 100644 index 0000000000..12db1ef9b1 --- /dev/null +++ b/testData/results/pkg/TestTryWithResourcesLoopJ16.dec @@ -0,0 +1,627 @@ +package pkg; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +public class TestTryWithResourcesLoopJ16 { + public void test(File f) throws FileNotFoundException { + while(true) { + Scanner s = this.create(f); + + label41: { + try { + if (!s.hasNext()) {// 11 + break label41; + } + + s.next();// 15 + } catch (Throwable var6) {// 10 + if (s != null) { + try { + s.close(); + } catch (Throwable var5) { + var6.addSuppressed(var5); + } + } + + throw var6; + } + + if (s != null) {// 16 + s.close(); + } + continue; + } + + if (s != null) { + s.close(); + } + + return;// 18 + } + } + + public void test1(File f) throws FileNotFoundException { + while(f.exists()) {// 21 + Scanner s = this.create(f); + + label40: { + try { + if (s.hasNext()) {// 23 + s.next();// 27 + break label40; + } + } catch (Throwable var6) {// 22 + if (s != null) { + try { + s.close(); + } catch (Throwable var5) { + var6.addSuppressed(var5); + } + } + + throw var6; + } + + if (s != null) { + s.close(); + } + break; + } + + if (s != null) {// 28 + s.close(); + } + } + + }// 30 + + public void test2(File f) throws FileNotFoundException { + while(f.exists()) {// 33 + Scanner s = this.create(f); + + label67: { + try { + Scanner s2 = this.create(f);// 35 + + label74: { + try { + if (!s.hasNext()) {// 36 + break label74; + } + + s.next();// 40 + } catch (Throwable var8) { + if (s2 != null) { + try { + s2.close(); + } catch (Throwable var7) { + var8.addSuppressed(var7); + } + } + + throw var8; + } + + if (s2 != null) { + s2.close(); + } + break label67; + } + + if (s2 != null) { + s2.close(); + } + } catch (Throwable var9) {// 34 + if (s != null) { + try { + s.close(); + } catch (Throwable var6) { + var9.addSuppressed(var6); + } + } + + throw var9; + } + + if (s != null) { + s.close(); + } + break; + } + + if (s != null) {// 41 + s.close(); + } + } + + }// 43 + + public void test3(File f) throws FileNotFoundException { + while(f.exists()) {// 46 + Scanner s = this.create(f); + + label91: { + label84: { + try { + Scanner s2; + label93: { + s2 = this.create(f);// 48 + + label94: { + try { + if (!s.hasNext()) {// 49 + break label93; + } + + if (s2.hasNext()) {// 51 + break label94; + } + + s.next();// 55 + } catch (Throwable var8) { + if (s2 != null) { + try { + s2.close(); + } catch (Throwable var7) { + var8.addSuppressed(var7); + } + } + + throw var8; + } + + if (s2 != null) { + s2.close(); + } + break label84; + } + + if (s2 != null) { + s2.close(); + } + break label91; + } + + if (s2 != null) { + s2.close(); + } + } catch (Throwable var9) {// 47 + if (s != null) { + try { + s.close(); + } catch (Throwable var6) { + var9.addSuppressed(var6); + } + } + + throw var9; + } + + if (s != null) { + s.close(); + } + break; + } + + if (s != null) {// 56 + s.close(); + } + continue; + } + + if (s != null) { + s.close(); + } + + return;// 52 + } + + }// 58 + + public void test4(File f) throws FileNotFoundException { + while(f.exists()) {// 61 + Scanner s = this.create(f); + + label74: { + try { + Scanner s2 = this.create(f);// 63 + + label76: { + try { + if (s.hasNext()) {// 64 + s.next();// 68 + break label76; + } + } catch (Throwable var8) { + if (s2 != null) { + try { + s2.close(); + } catch (Throwable var7) { + var8.addSuppressed(var7); + } + } + + throw var8; + } + + if (s2 != null) { + s2.close(); + } + break label74; + } + + if (s2 != null) { + s2.close(); + } + } catch (Throwable var9) {// 62 + if (s != null) { + try { + s.close(); + } catch (Throwable var6) { + var9.addSuppressed(var6); + } + } + + throw var9; + } + + if (s != null) {// 69 + s.close(); + } + continue; + } + + if (s != null) { + s.close(); + } + } + + }// 71 + + private Scanner create(File file) throws FileNotFoundException { + return new Scanner(file);// 74 + } +} + +class 'pkg/TestTryWithResourcesLoopJ16' { + method 'test (Ljava/io/File;)V' { + 0 9 + 1 9 + 2 9 + 3 9 + 4 9 + 5 9 + 6 13 + 7 13 + 8 13 + 9 13 + a 13 + d 36 + e 36 + 11 37 + 12 37 + 13 37 + 14 37 + 18 17 + 19 17 + 1a 17 + 1b 17 + 1d 30 + 1e 30 + 21 31 + 22 31 + 23 31 + 24 31 + 28 18 + 29 19 + 2a 19 + 2d 21 + 2e 21 + 34 22 + 39 23 + 3d 27 + 41 40 + } + + method 'test1 (Ljava/io/File;)V' { + 0 45 + 1 45 + 2 45 + 3 45 + 7 46 + 8 46 + 9 46 + a 46 + b 46 + c 46 + d 50 + e 50 + f 50 + 10 50 + 11 50 + 14 66 + 15 66 + 18 67 + 19 67 + 1a 67 + 1b 67 + 1f 51 + 20 51 + 21 51 + 22 51 + 24 72 + 25 72 + 28 73 + 29 73 + 2a 73 + 2b 73 + 2f 54 + 30 55 + 31 55 + 34 57 + 35 57 + 3b 58 + 40 59 + 44 63 + 48 77 + } + + method 'test2 (Ljava/io/File;)V' { + 0 80 + 1 80 + 2 80 + 3 80 + 7 81 + 8 81 + 9 81 + a 81 + b 81 + c 81 + d 85 + e 85 + f 85 + 10 85 + 11 85 + 12 85 + 13 89 + 14 89 + 15 89 + 16 89 + 17 89 + 1a 112 + 1b 112 + 1e 113 + 1f 113 + 22 127 + 23 127 + 26 128 + 27 128 + 28 128 + 29 128 + 2d 93 + 2e 93 + 2f 93 + 30 93 + 32 106 + 33 106 + 36 107 + 37 107 + 38 107 + 39 107 + 3d 94 + 3f 95 + 40 95 + 43 97 + 44 97 + 4a 98 + 50 99 + 55 103 + 56 133 + 57 133 + 5a 134 + 5b 134 + 5c 134 + 5d 134 + 61 115 + 62 116 + 63 116 + 66 118 + 67 118 + 6d 119 + 72 120 + 76 124 + 7a 138 + } + + method 'test3 (Ljava/io/File;)V' { + 0 141 + 1 141 + 2 141 + 3 141 + 7 142 + 8 142 + 9 142 + a 142 + b 142 + c 142 + d 149 + e 149 + f 149 + 10 149 + 11 149 + 12 149 + 13 153 + 14 153 + 15 153 + 16 153 + 17 153 + 1a 186 + 1b 186 + 1e 187 + 1f 187 + 22 201 + 23 201 + 26 202 + 27 202 + 28 202 + 29 202 + 2d 157 + 2e 157 + 2f 157 + 30 157 + 31 157 + 34 180 + 35 180 + 38 181 + 39 181 + 3c 213 + 3d 213 + 40 214 + 41 214 + 44 217 + 45 161 + 46 161 + 47 161 + 48 161 + 4a 174 + 4b 174 + 4e 175 + 4f 175 + 50 175 + 51 175 + 55 162 + 57 163 + 58 163 + 5b 165 + 5c 165 + 62 166 + 68 167 + 6d 171 + 6e 207 + 6f 207 + 72 208 + 73 208 + 74 208 + 75 208 + 79 189 + 7a 190 + 7b 190 + 7e 192 + 7f 192 + 85 193 + 8a 194 + 8e 198 + 92 220 + } + + method 'test4 (Ljava/io/File;)V' { + 0 223 + 1 223 + 2 223 + 3 223 + 7 224 + 8 224 + 9 224 + a 224 + b 224 + c 224 + d 228 + e 228 + f 228 + 10 228 + 11 228 + 12 228 + 13 232 + 14 232 + 15 232 + 16 232 + 17 232 + 1a 248 + 1b 248 + 1e 249 + 1f 249 + 22 275 + 23 275 + 26 276 + 27 276 + 28 276 + 29 276 + 2d 233 + 2e 233 + 2f 233 + 30 233 + 32 254 + 33 254 + 36 255 + 37 255 + 38 255 + 39 255 + 3d 236 + 3f 237 + 40 237 + 43 239 + 44 239 + 4a 240 + 50 241 + 55 245 + 56 269 + 57 269 + 5a 270 + 5b 270 + 5c 270 + 5d 270 + 61 257 + 62 258 + 63 258 + 66 260 + 67 260 + 6d 261 + 72 262 + 76 266 + 7a 280 + } + + method 'create (Ljava/io/File;)Ljava/util/Scanner;' { + 4 283 + 8 283 + } +} + +Lines mapping: +10 <-> 19 +11 <-> 14 +15 <-> 18 +16 <-> 31 +18 <-> 41 +21 <-> 46 +22 <-> 55 +23 <-> 51 +27 <-> 52 +28 <-> 73 +30 <-> 78 +33 <-> 81 +34 <-> 116 +35 <-> 86 +36 <-> 90 +40 <-> 94 +41 <-> 134 +43 <-> 139 +46 <-> 142 +47 <-> 190 +48 <-> 150 +49 <-> 154 +51 <-> 158 +52 <-> 218 +55 <-> 162 +56 <-> 208 +58 <-> 221 +61 <-> 224 +62 <-> 258 +63 <-> 229 +64 <-> 233 +68 <-> 234 +69 <-> 270 +71 <-> 281 +74 <-> 284 diff --git a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec index 612f36875e..238392661a 100644 --- a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec @@ -163,8 +163,109 @@ public class TestTryWithResourcesReturnJ16 { return o;// 61 } + public String testComplex1(File f, File f2, File f3) throws FileNotFoundException { + Scanner scanner = this.create(f); + + String var6; + label74: { + try { + Scanner s2 = this.create(f2);// 66 + + label76: { + try { + if (!scanner.hasNext() || !s2.hasNext()) {// 67 + s2.next();// 71 + break label76; + } + + var6 = scanner.next(); + } catch (Throwable var10) { + if (s2 != null) { + try { + s2.close(); + } catch (Throwable var9) { + var10.addSuppressed(var9); + } + } + + throw var10; + } + + if (s2 != null) { + s2.close(); + } + break label74; + } + + if (s2 != null) { + s2.close(); + } + } catch (Throwable var11) {// 65 + if (scanner != null) { + try { + scanner.close(); + } catch (Throwable var8) { + var11.addSuppressed(var8); + } + } + + throw var11; + } + + if (scanner != null) {// 72 + scanner.close(); + } + + return null;// 74 + } + + if (scanner != null) { + scanner.close(); + } + + return var6;// 68 + } + + public String testComplex2(File f, File f2, File f3) throws FileNotFoundException { + Scanner scanner = this.create(f); + + String var5; + label43: { + try { + if (scanner.hasNext()) {// 79 + var5 = scanner.next(); + break label43; + } + + scanner.next();// 83 + } catch (Throwable var8) {// 78 + if (scanner != null) { + try { + scanner.close(); + } catch (Throwable var7) { + var8.addSuppressed(var7); + } + } + + throw var8; + } + + if (scanner != null) {// 84 + scanner.close(); + } + + return null;// 86 + } + + if (scanner != null) { + scanner.close(); + } + + return var5;// 80 + } + private Scanner create(File file) throws FileNotFoundException { - return new Scanner(file);// 65 + return new Scanner(file);// 90 } } @@ -330,9 +431,160 @@ class 'pkg/TestTryWithResourcesReturnJ16' { e7 162 } - method 'create (Ljava/io/File;)Ljava/util/Scanner;' { + method 'testComplex1 (Ljava/io/File;Ljava/io/File;Ljava/io/File;)Ljava/lang/String;' { + 0 166 + 1 166 + 2 166 + 3 166 4 166 - 8 166 + 5 166 + 6 166 + 7 171 + 8 171 + 9 171 + a 171 + b 171 + c 171 + d 171 + e 175 + f 175 + 10 175 + 11 175 + 12 175 + 13 175 + 16 175 + 17 175 + 18 175 + 19 175 + 1a 175 + 1b 175 + 1e 180 + 1f 180 + 20 180 + 21 180 + 22 180 + 23 180 + 24 180 + 25 193 + 26 193 + 27 193 + 2a 194 + 2b 194 + 2c 194 + 2f 221 + 30 221 + 31 221 + 34 222 + 35 222 + 36 222 + 39 225 + 3a 225 + 3b 225 + 3c 176 + 3d 176 + 3e 176 + 3f 176 + 40 176 + 42 199 + 43 199 + 44 199 + 47 200 + 48 200 + 49 200 + 4a 200 + 4b 200 + 4f 181 + 51 182 + 52 182 + 53 182 + 56 184 + 57 184 + 58 184 + 5e 185 + 64 186 + 69 190 + 6a 214 + 6b 214 + 6c 214 + 6f 215 + 70 215 + 71 215 + 72 215 + 73 215 + 77 202 + 79 203 + 7a 203 + 7b 203 + 7e 205 + 7f 205 + 80 205 + 86 206 + 8c 207 + 91 211 + 92 218 + 93 218 + } + + method 'testComplex2 (Ljava/io/File;Ljava/io/File;Ljava/io/File;)Ljava/lang/String;' { + 0 229 + 1 229 + 2 229 + 3 229 + 4 229 + 5 229 + 6 229 + 7 234 + 8 234 + 9 234 + a 234 + b 234 + c 234 + f 235 + 10 235 + 11 235 + 12 235 + 13 235 + 14 235 + 15 235 + 16 259 + 17 259 + 18 259 + 1b 260 + 1c 260 + 1d 260 + 20 263 + 21 263 + 22 263 + 23 239 + 24 239 + 25 239 + 26 239 + 27 239 + 29 252 + 2a 252 + 2b 252 + 2e 253 + 2f 253 + 30 253 + 31 253 + 32 253 + 36 240 + 38 241 + 39 241 + 3a 241 + 3d 243 + 3e 243 + 3f 243 + 45 244 + 4b 245 + 50 249 + 51 256 + 52 256 + } + + method 'create (Ljava/io/File;)Ljava/util/Scanner;' { + 4 267 + 8 267 } } @@ -355,7 +607,20 @@ Lines mapping: 57 <-> 117 59 <-> 159 61 <-> 163 -65 <-> 167 +65 <-> 203 +66 <-> 172 +67 <-> 176 +68 <-> 226 +71 <-> 177 +72 <-> 215 +74 <-> 219 +78 <-> 241 +79 <-> 235 +80 <-> 264 +83 <-> 240 +84 <-> 253 +86 <-> 257 +90 <-> 268 Not mapped: 11 17 diff --git a/testData/results/pkg/TestTryWithResourcesSwitchJ16.dec b/testData/results/pkg/TestTryWithResourcesSwitchJ16.dec new file mode 100644 index 0000000000..d3d57f067e --- /dev/null +++ b/testData/results/pkg/TestTryWithResourcesSwitchJ16.dec @@ -0,0 +1,385 @@ +package pkg; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +public class TestTryWithResourcesSwitchJ16 { + public void test(File f) throws FileNotFoundException { + try (Scanner s = this.create(f)) {// 9 + switch(s.nextInt()) {// 10 + case 1: + System.out.println("1");// 12 + break;// 13 + case 2: + System.out.println("2");// 15 + break;// 16 + default: + System.out.println("default");// 18 + } + } + + }// 21 + + public void test1(File f) throws FileNotFoundException { + Scanner s = this.create(f); + + label43: { + label42: { + try { + switch(s.nextInt()) {// 26 + case 1: + System.out.println("1");// 28 + break label42;// 29 + case 2: + System.out.println("2");// 31 + break; + default: + System.out.println("default");// 34 + break label42; + } + } catch (Throwable var6) {// 25 + if (s != null) { + try { + s.close(); + } catch (Throwable var5) { + var6.addSuppressed(var5); + } + } + + throw var6; + } + + if (s != null) { + s.close(); + } + break label43; + } + + if (s != null) {// 36 + s.close(); + } + } + + System.out.println("after");// 38 + if (f.exists()) {// 39 + System.out.println("exists");// 40 + } + + }// 42 + + public int test2(File f) throws FileNotFoundException { + Scanner s = this.create(f); + + byte var3; + label57: { + label52: { + label51: { + try { + switch(s.nextInt()) {// 47 + case 1: + System.out.println("1");// 49 + break label51;// 50 + case 2: + System.out.println("2");// 52 + break; + case 3: + System.out.println("3");// 55 + var3 = 1; + break label57; + default: + System.out.println("default");// 58 + break label51; + } + } catch (Throwable var6) {// 46 + if (s != null) { + try { + s.close(); + } catch (Throwable var5) { + var6.addSuppressed(var5); + } + } + + throw var6; + } + + if (s != null) { + s.close(); + } + break label52; + } + + if (s != null) {// 60 + s.close(); + } + } + + System.out.println("after");// 62 + if (f.exists()) {// 63 + System.out.println("exists");// 64 + } + + return 0;// 67 + } + + if (s != null) { + s.close(); + } + + return var3;// 56 + } + + private Scanner create(File file) throws FileNotFoundException { + return new Scanner(file);// 71 + } +} + +class 'pkg/TestTryWithResourcesSwitchJ16' { + method 'test (Ljava/io/File;)V' { + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 8 + 6 9 + 7 9 + 8 9 + 9 9 + a 9 + 24 11 + 25 11 + 26 11 + 27 11 + 28 11 + 29 11 + 2a 11 + 2b 11 + 2c 12 + 2f 14 + 30 14 + 31 14 + 32 14 + 33 14 + 34 14 + 35 14 + 36 14 + 37 15 + 3a 17 + 3b 17 + 3c 17 + 3d 17 + 3e 17 + 3f 17 + 63 21 + } + + method 'test1 (Ljava/io/File;)V' { + 0 24 + 1 24 + 2 24 + 3 24 + 4 24 + 5 24 + 6 29 + 7 29 + 8 29 + 9 29 + a 29 + 24 31 + 25 31 + 26 31 + 27 31 + 28 31 + 29 31 + 2a 31 + 2b 31 + 2c 32 + 2f 34 + 30 34 + 31 34 + 32 34 + 33 34 + 34 34 + 37 52 + 38 52 + 3b 53 + 3c 53 + 3d 53 + 3e 53 + 42 37 + 43 37 + 44 37 + 45 37 + 46 37 + 47 37 + 4a 58 + 4b 58 + 4e 59 + 4f 59 + 50 59 + 51 59 + 55 40 + 56 41 + 57 41 + 5a 43 + 5b 43 + 61 44 + 66 45 + 6a 49 + 6b 63 + 6c 63 + 6d 63 + 6e 63 + 6f 63 + 70 63 + 71 63 + 72 63 + 73 64 + 74 64 + 75 64 + 76 64 + 77 64 + 7a 65 + 7b 65 + 7c 65 + 7d 65 + 7e 65 + 7f 65 + 82 68 + } + + method 'test2 (Ljava/io/File;)I' { + 0 71 + 1 71 + 2 71 + 3 71 + 4 71 + 5 71 + 6 78 + 7 78 + 8 78 + 9 78 + a 78 + 24 80 + 25 80 + 26 80 + 27 80 + 28 80 + 29 80 + 2a 80 + 2b 80 + 2c 81 + 2f 83 + 30 83 + 31 83 + 32 83 + 33 83 + 34 83 + 37 105 + 38 105 + 3b 106 + 3c 106 + 3d 106 + 3e 106 + 42 86 + 43 86 + 44 86 + 45 86 + 46 86 + 47 86 + 48 86 + 49 86 + 4a 87 + 4b 87 + 4c 124 + 4d 124 + 50 125 + 51 125 + 54 128 + 55 128 + 56 90 + 57 90 + 58 90 + 59 90 + 5a 90 + 5b 90 + 5e 111 + 5f 111 + 62 112 + 63 112 + 64 112 + 65 112 + 69 93 + 6a 94 + 6b 94 + 6e 96 + 6f 96 + 75 97 + 7a 98 + 7e 102 + 7f 116 + 80 116 + 81 116 + 82 116 + 83 116 + 84 116 + 85 116 + 86 116 + 87 117 + 88 117 + 89 117 + 8a 117 + 8b 117 + 8e 118 + 8f 118 + 90 118 + 91 118 + 92 118 + 93 118 + 96 121 + 97 121 + } + + method 'create (Ljava/io/File;)Ljava/util/Scanner;' { + 4 132 + 8 132 + } +} + +Lines mapping: +9 <-> 9 +10 <-> 10 +12 <-> 12 +13 <-> 13 +15 <-> 15 +16 <-> 16 +18 <-> 18 +21 <-> 22 +25 <-> 41 +26 <-> 30 +28 <-> 32 +29 <-> 33 +31 <-> 35 +34 <-> 38 +36 <-> 59 +38 <-> 64 +39 <-> 65 +40 <-> 66 +42 <-> 69 +46 <-> 94 +47 <-> 79 +49 <-> 81 +50 <-> 82 +52 <-> 84 +55 <-> 87 +56 <-> 129 +58 <-> 91 +60 <-> 112 +62 <-> 117 +63 <-> 118 +64 <-> 119 +67 <-> 122 +71 <-> 133 +Not mapped: +20 diff --git a/testData/src/java16/pkg/TestTryWithResourcesLoopJ16.java b/testData/src/java16/pkg/TestTryWithResourcesLoopJ16.java new file mode 100644 index 0000000000..7d77d32c53 --- /dev/null +++ b/testData/src/java16/pkg/TestTryWithResourcesLoopJ16.java @@ -0,0 +1,76 @@ +package pkg; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +public class TestTryWithResourcesLoopJ16 { + public void test(File f) throws FileNotFoundException { + while (true) { + try (Scanner s = create(f)) { + if (!s.hasNext()) { + break; + } + + s.next(); + } + } + } + + public void test1(File f) throws FileNotFoundException { + while (f.exists()) { + try (Scanner s = create(f)) { + if (!s.hasNext()) { + break; + } + + s.next(); + } + } + } + + public void test2(File f) throws FileNotFoundException { + while (f.exists()) { + try (Scanner s = create(f); + Scanner s2 = create(f)) { + if (!s.hasNext()) { + break; + } + + s.next(); + } + } + } + + public void test3(File f) throws FileNotFoundException { + while (f.exists()) { + try (Scanner s = create(f); + Scanner s2 = create(f)) { + if (!s.hasNext()) { + break; + } else if (s2.hasNext()) { + return; + } + + s.next(); + } + } + } + + public void test4(File f) throws FileNotFoundException { + while (f.exists()) { + try (Scanner s = create(f); + Scanner s2 = create(f)) { + if (!s.hasNext()) { + continue; + } + + s.next(); + } + } + } + + private Scanner create(File file) throws FileNotFoundException { + return new Scanner(file); + } +} diff --git a/testData/src/java16/pkg/TestTryWithResourcesReturnJ16.java b/testData/src/java16/pkg/TestTryWithResourcesReturnJ16.java index 91f5ccd963..bbe1201689 100644 --- a/testData/src/java16/pkg/TestTryWithResourcesReturnJ16.java +++ b/testData/src/java16/pkg/TestTryWithResourcesReturnJ16.java @@ -61,6 +61,31 @@ public String testComplex(File f, File f2, File f3) throws FileNotFoundException return o; } + public String testComplex1(File f, File f2, File f3) throws FileNotFoundException { + try (Scanner scanner = create(f); + Scanner s2 = create(f2)) { + if ((scanner.hasNext() && s2.hasNext())) { + return scanner.next(); + } + + s2.next(); + } + + return null; + } + + public String testComplex2(File f, File f2, File f3) throws FileNotFoundException { + try (Scanner scanner = create(f)) { + if ((scanner.hasNext())) { + return scanner.next(); + } + + scanner.next(); + } + + return null; + } + private Scanner create(File file) throws FileNotFoundException { return new Scanner(file); } diff --git a/testData/src/java16/pkg/TestTryWithResourcesSwitchJ16.java b/testData/src/java16/pkg/TestTryWithResourcesSwitchJ16.java new file mode 100644 index 0000000000..1f5513bbb9 --- /dev/null +++ b/testData/src/java16/pkg/TestTryWithResourcesSwitchJ16.java @@ -0,0 +1,73 @@ +package pkg; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +public class TestTryWithResourcesSwitchJ16 { + public void test(File f) throws FileNotFoundException { + try (Scanner s = create(f)) { + switch (s.nextInt()) { + case 1: + System.out.println("1"); + break; + case 2: + System.out.println("2"); + break; + default: + System.out.println("default"); + } + } + } + + public void test1(File f) throws FileNotFoundException { + label: + try (Scanner s = create(f)) { + switch (s.nextInt()) { + case 1: + System.out.println("1"); + break; + case 2: + System.out.println("2"); + break label; + default: + System.out.println("default"); + } + } + + System.out.println("after"); + if (f.exists()) { + System.out.println("exists"); + } + } + + public int test2(File f) throws FileNotFoundException { + label: + try (Scanner s = create(f)) { + switch (s.nextInt()) { + case 1: + System.out.println("1"); + break; + case 2: + System.out.println("2"); + break label; + case 3: + System.out.println("3"); + return 1; + default: + System.out.println("default"); + } + } + + System.out.println("after"); + if (f.exists()) { + System.out.println("exists"); + } + + return 0; + } + + private Scanner create(File file) throws FileNotFoundException { + return new Scanner(file); + } +} diff --git a/testData/src/java8/pkg/TestLoopFinally.java b/testData/src/java8/pkg/TestLoopFinally.java new file mode 100644 index 0000000000..50ddf79e8c --- /dev/null +++ b/testData/src/java8/pkg/TestLoopFinally.java @@ -0,0 +1,61 @@ +package pkg; + +public class TestLoopFinally { + public void test() { + for (int i = 0; i < 10; i++) { + try { + System.out.println(i); + } finally { + System.out.println("finally"); + + if (i == 5) { + break; + } + + System.out.println("finally2"); + } + } + + System.out.println("after"); + } + + public void test1() { + for (int i = 0; i < 10; i++) { + try { + System.out.println(i); + } finally { + System.out.println("finally"); + + if (i == 5) { + System.out.println("continue"); + continue; + } else if (i == 4) { + System.out.println("break"); + break; + } + + System.out.println("finally2"); + } + } + + System.out.println("after"); + } + + public void test2() { + for (int i = 0; i < 10; i++) { + try { + System.out.println(i); + } finally { + System.out.println("finally"); + + if (i == 5) { + break; + } + + continue; + } + } + + System.out.println("after"); + } +} diff --git a/testData/src/java8/pkg/TestSwitchFinally.java b/testData/src/java8/pkg/TestSwitchFinally.java new file mode 100644 index 0000000000..4aac1ddcc0 --- /dev/null +++ b/testData/src/java8/pkg/TestSwitchFinally.java @@ -0,0 +1,83 @@ +package pkg; + +public class TestSwitchFinally { + public void test(int i) { + try { + System.out.println(1); + } finally { + System.out.println("finally"); + + switch (i) { + case 0: + System.out.println("0"); + break; + } + + System.out.println("b"); + } + } + + public void test1(int i) { + try { + System.out.println(1); + } finally { + System.out.println("finally"); + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + break; + } + + System.out.println("b"); + } + } + + public void test2(int i) { + try { + System.out.println(1); + } finally { + System.out.println("finally"); + + switch (i) { + default: + System.out.println("default"); + } + + System.out.println("b"); + } + } + + public int test3(int i) { + label: { + try { + System.out.println(1); + } finally { + System.out.println("finally"); + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + break label; + default: + System.out.println("Default"); + } + + System.out.println("b"); + + } + + System.out.println("d"); + return 1; + } + + System.out.println("c"); + return 0; + } +} diff --git a/testData/src/java8/pkg/TestSwitchLoop.java b/testData/src/java8/pkg/TestSwitchLoop.java new file mode 100644 index 0000000000..c8e002573e --- /dev/null +++ b/testData/src/java8/pkg/TestSwitchLoop.java @@ -0,0 +1,248 @@ +package pkg; + +public class TestSwitchLoop { + public void test(int i) { + while (i > 0) { + i--; + + switch (i) { + case 0: + System.out.println("0"); + continue; + case 1: + System.out.println("1"); + continue; + case 2: + System.out.println("2"); + continue; + } + + System.out.println("after"); + if (i == 4) { + break; + } + } + } + + public int test2(int i) { + loop: + for (int a = 0; i > a; a++) { + i--; + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + return 1; + case 2: + System.out.println("2"); + return 2; + case 3: + System.out.println("3"); + break loop; + case 4: + System.out.println("4"); + break loop; + } + + System.out.println("after"); + } + + return 0; + } + + public int test3(int i) { + loop: + for (int a = 0; i > a; a++) { + i--; + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + return 1; + case 2: + System.out.println("2"); + return 2; + case 3: + System.out.println("3"); + break loop; + case 4: + System.out.println("4"); + break loop; + } + + System.out.println("after"); + } + + System.out.println("after2"); + + return 0; + } + + public void test4(int i) { + for (int a = 0; i > a; a++) { + i--; + + switch (i) { + case 0: + System.out.println("0"); + if (a == 0) { + continue; + } + + break; + case 1: + System.out.println("1"); + } + + System.out.println("after"); + } + + System.out.println("after2"); + } + + public void test5(int i) { + loop: + for (int a = 0; i > a; a++) { + i--; + + switch (i) { + case 0: + System.out.println("0"); + for (int i1 = 0; i1 < 5; i1++) { + switch (i1) { + case 0: + System.out.println(0); + break; + case 1: + System.out.println(1); + break loop; + case 2: + return; + } + } + + break; + case 1: + System.out.println("1"); + } + + System.out.println("after"); + } + + System.out.println("after2"); + } + + public void test6() { + loop: + for (int i = 0; i < 10; i++) { + + switch (i) { + case 0: + System.out.println("0"); + for (int i1 = 0; i1 < 5; i1++) { + switch (i1) { + case 1: + System.out.println(1); + break loop; + } + } + + break; + } + + System.out.println("after"); + } + + System.out.println("after2"); + } + + public void test7() { + loop: + for (int i = 0; i < 10; i++) { + for (int i1 = 0; i1 < 5; i1++) { + switch (i1) { + case 1: + System.out.println(1); + break loop; + } + } + + System.out.println("after"); + } + + System.out.println("after2"); + } + + public void test8(int i) { + switch (i) { + case 0: + label: { + for (int j = 0; j < 10; j++) { + if (j == 3) { + break label; + } + } + + System.out.println(0); + } + System.out.println("after"); + case 1: + System.out.println(1); + } + + System.out.println("after2"); + } + + public void test9(int i) { + switch (i) { + case 0: + label: { + for (int j = 0; j < 10; j++) { + if (j == 3) { + break label; + } + } + + System.out.println(0); + break; + } + System.out.println("after"); + case 1: + System.out.println(1); + } + + System.out.println("after2"); + } + + public void test10(int i) { + switch (i) { + case 0: + label: { + for (int j = 0; j < 10; j++) { + if (j == 3) { + break label; + } + + if (j == 9) { + break; + } + } + + System.out.println(0); + break; + } + + System.out.println("after"); + case 1: + System.out.println(1); + } + + System.out.println("after2"); + } +} From 03c09975ccfbece5b06ad75e9c437fd2f179a143 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sun, 21 Nov 2021 10:25:31 -0500 Subject: [PATCH 35/85] Bump default line length to 160 --- .../main/extern/IFernflowerPreferences.java | 2 +- testData/kt25937/kt/Kt25937Kt.java | 4 +- testData/kt25937/kt/Kt25937_1Kt.java | 50 ++- .../pkg/TestAnonymousClassConstructor.dec | 378 +++++++++--------- .../pkg/TestBinaryOperationWrapping.dec | 136 ++++--- testData/results/pkg/TestIfLoop.dec | 191 +++++---- testData/results/pkg/TestMethodHandles.dec | 62 ++- testData/results/pkg/TestSuspendLambdaKt.dec | 138 ++++--- .../pkg/TestSwitchPatternMatching2.dec | 140 ++++--- testData/results/pkg/TestTextBlocks.dec | 32 +- .../pkg/TestBinaryOperationWrapping.java | 4 +- 11 files changed, 558 insertions(+), 579 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java index 4994414926..fd25b773bf 100644 --- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java +++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java @@ -116,7 +116,7 @@ static Map getDefaults() { defaults.put(RENAME_ENTITIES, "0"); defaults.put(NEW_LINE_SEPARATOR, (InterpreterUtil.IS_WINDOWS ? "0" : "1")); defaults.put(INDENT_STRING, " "); - defaults.put(PREFERRED_LINE_LENGTH, "120"); + defaults.put(PREFERRED_LINE_LENGTH, "160"); defaults.put(BANNER, ""); defaults.put(UNIT_TEST_MODE, "0"); defaults.put(DUMP_ORIGINAL_LINES, "0"); diff --git a/testData/kt25937/kt/Kt25937Kt.java b/testData/kt25937/kt/Kt25937Kt.java index aaa4570696..4855c45d9f 100644 --- a/testData/kt25937/kt/Kt25937Kt.java +++ b/testData/kt25937/kt/Kt25937Kt.java @@ -15,9 +15,7 @@ d2 = {"callSuspendBlock", "", "block", "Lkotlin/Function1;", "Lkotlin/coroutines/Continuation;", "", "", "(Lkotlin/jvm/functions/Function1;)I", "callSuspendBlockGood", "kotlinx-test"} ) public final class Kt25937Kt { - public static final int callSuspendBlock( - @NotNull Function1, ? extends Object> block - ) { + public static final int callSuspendBlock(@NotNull Function1, ? extends Object> block) { Intrinsics.checkParameterIsNotNull(block, "block"); return 1; } diff --git a/testData/kt25937/kt/Kt25937_1Kt.java b/testData/kt25937/kt/Kt25937_1Kt.java index d8dcae2d7c..ea79e6ed53 100644 --- a/testData/kt25937/kt/Kt25937_1Kt.java +++ b/testData/kt25937/kt/Kt25937_1Kt.java @@ -19,32 +19,30 @@ ) public final class Kt25937_1Kt { public static final int some1() { - return Kt25937Kt.callSuspendBlock( - (Function1)(new Function1, Object>((Continuation)null) { - int label; - - @Nullable - public final Object invokeSuspend(@NotNull Object $result) { - Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); - switch(this.label) { - case 0: - ResultKt.throwOnFailure($result); - return Unit.INSTANCE; - default: - throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); - } - } - - @NotNull - public final Continuation create(@NotNull Continuation completion) { - Intrinsics.checkParameterIsNotNull(completion, "completion"); - return new (completion); - } - - public final Object invoke(Object var1) { - return (()this.create((Continuation)var1)).invokeSuspend(Unit.INSTANCE); + return Kt25937Kt.callSuspendBlock((Function1)(new Function1, Object>((Continuation)null) { + int label; + + @Nullable + public final Object invokeSuspend(@NotNull Object $result) { + Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); + switch(this.label) { + case 0: + ResultKt.throwOnFailure($result); + return Unit.INSTANCE; + default: + throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); } - }) - ); + } + + @NotNull + public final Continuation create(@NotNull Continuation completion) { + Intrinsics.checkParameterIsNotNull(completion, "completion"); + return new (completion); + } + + public final Object invoke(Object var1) { + return (()this.create((Continuation)var1)).invokeSuspend(Unit.INSTANCE); + } + })); } } diff --git a/testData/results/pkg/TestAnonymousClassConstructor.dec b/testData/results/pkg/TestAnonymousClassConstructor.dec index cdc5aeba47..e0ab2c8e78 100644 --- a/testData/results/pkg/TestAnonymousClassConstructor.dec +++ b/testData/results/pkg/TestAnonymousClassConstructor.dec @@ -2,9 +2,7 @@ package pkg; class TestAnonymousClassConstructor { void innerPrivateString() { - TestAnonymousClassConstructor.InnerPrivateString var10001 = new TestAnonymousClassConstructor.InnerPrivateString( - "text"// 5 - ) { + TestAnonymousClassConstructor.InnerPrivateString var10001 = new TestAnonymousClassConstructor.InnerPrivateString("text") {// 5 }; }// 6 @@ -14,37 +12,27 @@ class TestAnonymousClassConstructor { }// 10 void innerStaticPrivateString() { - TestAnonymousClassConstructor.InnerStaticPrivateString var10001 = new TestAnonymousClassConstructor.InnerStaticPrivateString( - "text"// 13 - ) { + TestAnonymousClassConstructor.InnerStaticPrivateString var10001 = new TestAnonymousClassConstructor.InnerStaticPrivateString("text") {// 13 }; }// 14 void innerStaticPrivate() { - TestAnonymousClassConstructor.InnerStaticPrivate var10001 = new TestAnonymousClassConstructor.InnerStaticPrivate( - 3L, 4// 17 - ) { + TestAnonymousClassConstructor.InnerStaticPrivate var10001 = new TestAnonymousClassConstructor.InnerStaticPrivate(3L, 4) {// 17 }; }// 18 static void innerStaticPrivateStringStatic() { - TestAnonymousClassConstructor.InnerStaticPrivateString var10001 = new TestAnonymousClassConstructor.InnerStaticPrivateString( - "text"// 21 - ) { + TestAnonymousClassConstructor.InnerStaticPrivateString var10001 = new TestAnonymousClassConstructor.InnerStaticPrivateString("text") {// 21 }; }// 22 static void innerStaticPrivateStatic() { - TestAnonymousClassConstructor.InnerStaticPrivate var10001 = new TestAnonymousClassConstructor.InnerStaticPrivate( - 3L, 4// 25 - ) { + TestAnonymousClassConstructor.InnerStaticPrivate var10001 = new TestAnonymousClassConstructor.InnerStaticPrivate(3L, 4) {// 25 }; }// 26 void innerPublicString() { - TestAnonymousClassConstructor.InnerPublicString var10001 = new TestAnonymousClassConstructor.InnerPublicString( - "text"// 29 - ) { + TestAnonymousClassConstructor.InnerPublicString var10001 = new TestAnonymousClassConstructor.InnerPublicString("text") {// 29 }; }// 30 @@ -54,30 +42,22 @@ class TestAnonymousClassConstructor { }// 34 void innerStaticPublicString() { - TestAnonymousClassConstructor.InnerStaticPublicString var10001 = new TestAnonymousClassConstructor.InnerStaticPublicString( - "text"// 37 - ) { + TestAnonymousClassConstructor.InnerStaticPublicString var10001 = new TestAnonymousClassConstructor.InnerStaticPublicString("text") {// 37 }; }// 38 void innerStaticPublic() { - TestAnonymousClassConstructor.InnerStaticPublic var10001 = new TestAnonymousClassConstructor.InnerStaticPublic( - 3L, 4// 41 - ) { + TestAnonymousClassConstructor.InnerStaticPublic var10001 = new TestAnonymousClassConstructor.InnerStaticPublic(3L, 4) {// 41 }; }// 42 static void innerStaticPublicStringStatic() { - TestAnonymousClassConstructor.InnerStaticPublicString var10001 = new TestAnonymousClassConstructor.InnerStaticPublicString( - "text"// 45 - ) { + TestAnonymousClassConstructor.InnerStaticPublicString var10001 = new TestAnonymousClassConstructor.InnerStaticPublicString("text") {// 45 }; }// 46 static void innerStaticPublicStatic() { - TestAnonymousClassConstructor.InnerStaticPublic var10001 = new TestAnonymousClassConstructor.InnerStaticPublic( - 3L, 4// 49 - ) { + TestAnonymousClassConstructor.InnerStaticPublic var10001 = new TestAnonymousClassConstructor.InnerStaticPublic(3L, 4) {// 49 }; }// 50 @@ -136,255 +116,255 @@ class TestAnonymousClassConstructor { class 'pkg/TestAnonymousClassConstructor' { method 'innerPrivateString ()V' { - 5 5 - 6 5 - b 8 + 5 4 + 6 4 + b 6 } method 'innerPrivate ()V' { - 5 11 - 6 11 - 7 11 - 8 11 - d 13 + 5 9 + 6 9 + 7 9 + 8 9 + d 11 } method 'innerStaticPrivateString ()V' { - 5 17 - 6 17 - b 20 + 5 14 + 6 14 + b 16 } method 'innerStaticPrivate ()V' { - 5 24 - 6 24 - 7 24 - 8 24 - d 27 + 5 19 + 6 19 + 7 19 + 8 19 + d 21 } method 'innerStaticPrivateStringStatic ()V' { - 4 31 - 5 31 - a 34 + 4 24 + 5 24 + a 26 } method 'innerStaticPrivateStatic ()V' { - 4 38 - 5 38 - 6 38 - 7 38 - c 41 + 4 29 + 5 29 + 6 29 + 7 29 + c 31 } method 'innerPublicString ()V' { - 5 45 - 6 45 - b 48 + 5 34 + 6 34 + b 36 } method 'innerPublic ()V' { - 5 51 - 6 51 - 7 51 - 8 51 - d 53 + 5 39 + 6 39 + 7 39 + 8 39 + d 41 } method 'innerStaticPublicString ()V' { - 5 57 - 6 57 - b 60 + 5 44 + 6 44 + b 46 } method 'innerStaticPublic ()V' { - 5 64 - 6 64 - 7 64 - 8 64 - d 67 + 5 49 + 6 49 + 7 49 + 8 49 + d 51 } method 'innerStaticPublicStringStatic ()V' { - 4 71 - 5 71 - a 74 + 4 54 + 5 54 + a 56 } method 'innerStaticPublicStatic ()V' { - 4 78 - 5 78 - 6 78 - 7 78 - c 81 + 4 59 + 5 59 + 6 59 + 7 59 + c 61 } method 'n (Ljava/lang/String;)V' { - 0 84 - 1 84 - 2 84 - a 84 - b 84 - f 84 - 13 84 - 14 84 - 15 84 - 16 84 - 17 84 - 18 84 - 19 85 + 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 89 - 14 89 - 15 89 - 19 89 - 1a 89 - 1e 89 - 1f 89 - 20 89 - 21 89 - 22 89 - 23 89 - 24 90 + 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 95 - a 95 - b 95 - c 95 - d 96 + 9 75 + a 75 + b 75 + c 75 + d 76 } } class 'pkg/TestAnonymousClassConstructor$InnerPublic' { method ' (Lpkg/TestAnonymousClassConstructor;JI)V' { - 10 101 - 14 101 - 15 101 - 19 101 - 1a 101 - 1e 101 - 1f 101 - 20 101 - 21 101 - 22 101 - 23 101 - 24 102 + 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 107 - a 107 - b 107 - c 107 - d 108 + 9 87 + a 87 + b 87 + c 87 + d 88 } } class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivate' { method ' (JI)V' { - b 113 - f 113 - 10 113 - 14 113 - 18 113 - 19 113 - 1a 113 - 1b 113 - 1c 113 - 1d 113 - 1e 114 + 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 119 - 5 119 - 6 119 - 7 119 - 8 120 + 4 99 + 5 99 + 6 99 + 7 99 + 8 100 } } class 'pkg/TestAnonymousClassConstructor$InnerStaticPublic' { method ' (JI)V' { - b 125 - f 125 - 10 125 - 14 125 - 18 125 - 19 125 - 1a 125 - 1b 125 - 1c 125 - 1d 125 - 1e 126 + 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 131 - 5 131 - 6 131 - 7 131 - 8 132 + 4 111 + 5 111 + 6 111 + 7 111 + 8 112 } } Lines mapping: -5 <-> 6 -6 <-> 9 -9 <-> 12 -10 <-> 14 -13 <-> 18 -14 <-> 21 -17 <-> 25 -18 <-> 28 -21 <-> 32 -22 <-> 35 -25 <-> 39 -26 <-> 42 -29 <-> 46 -30 <-> 49 -33 <-> 52 -34 <-> 54 -37 <-> 58 -38 <-> 61 -41 <-> 65 -42 <-> 68 -45 <-> 72 -46 <-> 75 -49 <-> 79 -50 <-> 82 -53 <-> 85 -54 <-> 86 -58 <-> 96 -59 <-> 97 -64 <-> 90 -65 <-> 91 -70 <-> 120 -71 <-> 121 -76 <-> 114 -77 <-> 115 -82 <-> 108 -83 <-> 109 -88 <-> 102 -89 <-> 103 -94 <-> 132 -95 <-> 133 -100 <-> 126 -101 <-> 127 +5 <-> 5 +6 <-> 7 +9 <-> 10 +10 <-> 12 +13 <-> 15 +14 <-> 17 +17 <-> 20 +18 <-> 22 +21 <-> 25 +22 <-> 27 +25 <-> 30 +26 <-> 32 +29 <-> 35 +30 <-> 37 +33 <-> 40 +34 <-> 42 +37 <-> 45 +38 <-> 47 +41 <-> 50 +42 <-> 52 +45 <-> 55 +46 <-> 57 +49 <-> 60 +50 <-> 62 +53 <-> 65 +54 <-> 66 +58 <-> 76 +59 <-> 77 +64 <-> 70 +65 <-> 71 +70 <-> 100 +71 <-> 101 +76 <-> 94 +77 <-> 95 +82 <-> 88 +83 <-> 89 +88 <-> 82 +89 <-> 83 +94 <-> 112 +95 <-> 113 +100 <-> 106 +101 <-> 107 Not mapped: 57 63 diff --git a/testData/results/pkg/TestBinaryOperationWrapping.dec b/testData/results/pkg/TestBinaryOperationWrapping.dec index c21bfe4cde..1c0cfa8f2a 100644 --- a/testData/results/pkg/TestBinaryOperationWrapping.dec +++ b/testData/results/pkg/TestBinaryOperationWrapping.dec @@ -39,7 +39,11 @@ public class TestBinaryOperationWrapping { boolean w, boolean x, boolean y, - boolean z + boolean z, + boolean a1, + boolean b1, + boolean c1, + boolean d1 ) { System.out// 12 .println( @@ -55,7 +59,9 @@ public class TestBinaryOperationWrapping { s && t || u && v || w && x || - y && z + y && z || + a1 && b1 || + c1 && d1 ); }// 13 } @@ -81,68 +87,76 @@ class 'pkg/TestBinaryOperationWrapping' { 29 13 } - method 'testBooleanOperation (ZZZZZZZZZZZZZZZZZZZZZZZZZZ)V' { - 0 43 - 1 43 - 2 43 - 3 45 - 7 45 - b 46 - f 46 - 10 46 - 14 47 - 15 47 - 19 47 - 1a 47 - 1e 48 - 1f 48 - 23 48 - 24 48 - 28 49 - 29 49 - 2d 49 - 2e 49 - 32 50 - 33 50 - 37 50 - 38 50 - 3c 51 - 3d 51 - 41 51 - 42 51 - 46 52 - 47 52 - 4b 52 - 4c 52 - 50 53 - 51 53 - 55 53 - 56 53 - 5a 54 - 5b 54 - 5f 54 - 60 54 - 64 55 - 65 55 - 69 55 - 6a 55 - 6e 56 - 6f 56 - 73 56 - 74 56 - 78 57 - 79 57 - 7d 57 - 7e 57 - 87 44 - 88 44 - 89 44 - 8a 59 + method 'testBooleanOperation (ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ)V' { + 0 47 + 1 47 + 2 47 + 3 49 + 7 49 + b 50 + f 50 + 10 50 + 14 51 + 15 51 + 19 51 + 1a 51 + 1e 52 + 1f 52 + 23 52 + 24 52 + 28 53 + 29 53 + 2d 53 + 2e 53 + 32 54 + 33 54 + 37 54 + 38 54 + 3c 55 + 3d 55 + 41 55 + 42 55 + 46 56 + 47 56 + 4b 56 + 4c 56 + 50 57 + 51 57 + 55 57 + 56 57 + 5a 58 + 5b 58 + 5f 58 + 60 58 + 64 59 + 65 59 + 69 59 + 6a 59 + 6e 60 + 6f 60 + 73 60 + 74 60 + 78 61 + 79 61 + 7d 61 + 7e 61 + 82 62 + 83 62 + 87 62 + 88 62 + 8c 63 + 8d 63 + 91 63 + 92 63 + 9b 48 + 9c 48 + 9d 48 + 9e 65 } } Lines mapping: 5 <-> 5 9 <-> 14 -12 <-> 44 -13 <-> 60 +12 <-> 48 +13 <-> 66 diff --git a/testData/results/pkg/TestIfLoop.dec b/testData/results/pkg/TestIfLoop.dec index f604e167a8..986a91917a 100644 --- a/testData/results/pkg/TestIfLoop.dec +++ b/testData/results/pkg/TestIfLoop.dec @@ -36,10 +36,7 @@ public class TestIfLoop { public void testCompound2(int a, int b, Random random) { a = random.nextInt(8) - random.nextInt(8) + a;// 41 - for(int var5 = random.nextInt(8) - random.nextInt(8) + b;// 42 - a >= 0 && a <= 20 && var5 >= 0 && var5 <= 20;// 44 - var5 -= random.nextInt(4) - random.nextInt(4)// 46 - ) { + for(int var5 = random.nextInt(8) - random.nextInt(8) + b; a >= 0 && a <= 20 && var5 >= 0 && var5 <= 20; var5 -= random.nextInt(4) - random.nextInt(4)) {// 42 44 46 a -= random.nextInt(4) - random.nextInt(4);// 45 } @@ -169,85 +166,85 @@ class 'pkg/TestIfLoop' { 1d 38 1e 38 1f 38 - 20 39 - 21 39 - 24 39 - 25 39 - 26 39 - 27 39 - 2a 39 - 2b 39 - 2e 39 - 2f 39 - 30 39 - 31 39 - 35 42 - 36 42 - 37 42 - 38 42 - 39 42 - 3a 42 - 3b 42 - 3c 42 - 3d 42 - 3e 42 - 3f 42 - 41 42 - 43 40 - 44 40 - 45 40 - 46 40 - 47 40 - 48 40 - 49 40 - 4a 40 - 4b 40 - 4c 40 - 4d 40 - 4f 40 - 53 45 + 20 38 + 21 38 + 24 38 + 25 38 + 26 38 + 27 38 + 2a 38 + 2b 38 + 2e 38 + 2f 38 + 30 38 + 31 38 + 35 39 + 36 39 + 37 39 + 38 39 + 39 39 + 3a 39 + 3b 39 + 3c 39 + 3d 39 + 3e 39 + 3f 39 + 41 39 + 43 38 + 44 38 + 45 38 + 46 38 + 47 38 + 48 38 + 49 38 + 4a 38 + 4b 38 + 4c 38 + 4d 38 + 4f 38 + 53 42 } method 'testElseIf (I)I' { - 0 48 - 1 48 - 4 49 - 5 49 - 6 49 - 7 49 - a 50 - b 50 - c 50 - 10 51 - 11 51 - 12 51 - 13 51 - 16 52 - 17 52 - 18 52 - 1c 53 - 1d 53 - 1e 53 - 1f 53 - 22 54 - 23 54 - 24 54 - 28 55 - 29 55 - 2a 55 - 2b 55 - 2f 56 - 31 56 - 35 58 - 36 58 - 37 58 - 38 58 - 3b 62 - 3c 62 - 3d 62 - 48 59 - 49 66 - 4a 66 + 0 45 + 1 45 + 4 46 + 5 46 + 6 46 + 7 46 + a 47 + b 47 + c 47 + 10 48 + 11 48 + 12 48 + 13 48 + 16 49 + 17 49 + 18 49 + 1c 50 + 1d 50 + 1e 50 + 1f 50 + 22 51 + 23 51 + 24 51 + 28 52 + 29 52 + 2a 52 + 2b 52 + 2f 53 + 31 53 + 35 55 + 36 55 + 37 55 + 38 55 + 3b 59 + 3c 59 + 3d 59 + 48 56 + 49 63 + 4a 63 } } @@ -269,20 +266,20 @@ Lines mapping: 37 <-> 33 41 <-> 37 42 <-> 39 -44 <-> 40 -45 <-> 43 -46 <-> 41 -48 <-> 46 -51 <-> 49 -52 <-> 50 -53 <-> 51 -54 <-> 52 -55 <-> 53 -56 <-> 54 -57 <-> 55 -58 <-> 56 -59 <-> 57 -60 <-> 59 -61 <-> 63 -63 <-> 60 -67 <-> 67 +44 <-> 39 +45 <-> 40 +46 <-> 39 +48 <-> 43 +51 <-> 46 +52 <-> 47 +53 <-> 48 +54 <-> 49 +55 <-> 50 +56 <-> 51 +57 <-> 52 +58 <-> 53 +59 <-> 54 +60 <-> 56 +61 <-> 60 +63 <-> 57 +67 <-> 64 diff --git a/testData/results/pkg/TestMethodHandles.dec b/testData/results/pkg/TestMethodHandles.dec index 7f5a00ea52..9bdcce0d15 100644 --- a/testData/results/pkg/TestMethodHandles.dec +++ b/testData/results/pkg/TestMethodHandles.dec @@ -36,9 +36,7 @@ public class TestMethodHandles { } public void test5() throws Throwable { - MethodHandle println = LOOKUP.findVirtual(// 36 - PrintStream.class, "println", MethodType.methodType(Void.TYPE, Long.TYPE) - ); + MethodHandle println = LOOKUP.findVirtual(PrintStream.class, "println", MethodType.methodType(Void.TYPE, Long.TYPE));// 36 int a = -5;// 37 println.invokeExact(System.out, (long)a);// 38 }// 39 @@ -199,36 +197,36 @@ class 'pkg/TestMethodHandles' { 0 38 1 38 2 38 - 3 39 - 4 39 - 5 39 - 6 39 - 7 39 - 8 39 - 9 39 - a 39 - b 39 - c 39 - d 39 - e 39 - f 39 + 3 38 + 4 38 + 5 38 + 6 38 + 7 38 + 8 38 + 9 38 + a 38 + b 38 + c 38 + d 38 + e 38 + f 38 10 38 11 38 12 38 13 38 - 14 41 - 15 41 - 16 41 - 17 42 - 18 42 - 19 42 - 1a 42 - 1b 42 - 1c 42 - 1d 42 - 1e 42 - 1f 42 - 20 43 + 14 39 + 15 39 + 16 39 + 17 40 + 18 40 + 19 40 + 1a 40 + 1b 40 + 1c 40 + 1d 40 + 1e 40 + 1f 40 + 20 41 } } @@ -250,6 +248,6 @@ Lines mapping: 31 <-> 34 32 <-> 35 36 <-> 39 -37 <-> 42 -38 <-> 43 -39 <-> 44 +37 <-> 40 +38 <-> 41 +39 <-> 42 diff --git a/testData/results/pkg/TestSuspendLambdaKt.dec b/testData/results/pkg/TestSuspendLambdaKt.dec index aca16adb51..21e2a18119 100644 --- a/testData/results/pkg/TestSuspendLambdaKt.dec +++ b/testData/results/pkg/TestSuspendLambdaKt.dec @@ -20,9 +20,7 @@ import org.jetbrains.annotations.Nullable; ) public final class TestSuspendLambdaKt { @NotNull - private static final Function1, Object> sl1 = new NamelessClass_1( - (Continuation)null - ); + private static final Function1, Object> sl1 = new NamelessClass_1((Continuation)null); @NotNull public static final Function1, Object> getSl1() { @@ -84,91 +82,91 @@ public final class TestSuspendLambdaKt { class 'pkg/TestSuspendLambdaKt' { method 'getSl1 ()Lkotlin/jvm/functions/Function1;' { - 0 28 - 1 28 - 2 28 - 3 28 + 0 26 + 1 26 + 2 26 + 3 26 } method ' ()V' { - e 81 + e 79 } } class 'pkg/TestSuspendLambdaKt$sl1$1' { method ' (Lkotlin/coroutines/Continuation;)V' { - 1 52 - 2 52 - 3 52 - 4 52 - 5 52 - 6 53 + 1 50 + 2 50 + 3 50 + 4 50 + 5 50 + 6 51 } method 'invokeSuspend (Ljava/lang/Object;)Ljava/lang/Object;' { - 0 57 - 1 57 - 2 57 - 3 57 - 4 57 - 5 58 - 6 58 - 7 58 - 8 58 - 9 58 - 1c 60 - 1d 60 - 1e 60 - 1f 60 - 20 61 - 21 61 - 22 61 - 23 62 - 24 62 - 25 63 - 26 63 - 27 63 - 28 63 - 29 63 - 2a 63 - 2b 63 - 2c 64 - 2d 64 - 2e 64 - 2f 64 - 34 66 - 35 66 - 39 66 + 0 55 + 1 55 + 2 55 + 3 55 + 4 55 + 5 56 + 6 56 + 7 56 + 8 56 + 9 56 + 1c 58 + 1d 58 + 1e 58 + 1f 58 + 20 59 + 21 59 + 22 59 + 23 60 + 24 60 + 25 61 + 26 61 + 27 61 + 28 61 + 29 61 + 2a 61 + 2b 61 + 2c 62 + 2d 62 + 2e 62 + 2f 62 + 34 64 + 35 64 + 39 64 } method 'create (Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;' { - 4 72 - 8 72 - 9 72 - a 72 - b 72 + 4 70 + 8 70 + 9 70 + a 70 + b 70 } method 'invoke (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;' { - 0 77 - 1 77 - 2 77 - 3 77 - 4 77 - 5 77 - 6 77 - 7 77 - 8 77 - 9 77 - a 77 - b 77 - c 77 - d 77 - e 77 + 0 75 + 1 75 + 2 75 + 3 75 + 4 75 + 5 75 + 6 75 + 7 75 + 8 75 + 9 75 + a 75 + b 75 + c 75 + d 75 + e 75 } } Lines mapping: -3 <-> 82 -4 <-> 62 -5 <-> 65 +3 <-> 80 +4 <-> 60 +5 <-> 63 diff --git a/testData/results/pkg/TestSwitchPatternMatching2.dec b/testData/results/pkg/TestSwitchPatternMatching2.dec index e540ec9d80..cfee549822 100644 --- a/testData/results/pkg/TestSwitchPatternMatching2.dec +++ b/testData/results/pkg/TestSwitchPatternMatching2.dec @@ -8,9 +8,7 @@ public class TestSwitchPatternMatching2 { byte var2 = 0; while(true) { - switch(SwitchBootstraps.typeSwitch<"typeSwitch",TestSwitchPatternMatching2.Triangle,TestSwitchPatternMatching2.Triangle>( - var1, var2 - )) { + switch(SwitchBootstraps.typeSwitch<"typeSwitch",TestSwitchPatternMatching2.Triangle,TestSwitchPatternMatching2.Triangle>(var1, var2)) { case -1: System.out.println("null");// 11 return;// 15 @@ -52,87 +50,87 @@ class 'pkg/TestSwitchPatternMatching2' { 1 6 2 7 3 7 - 4 11 - 5 11 + 4 10 + 5 10 6 10 7 10 8 10 9 10 a 10 b 10 - 24 17 - 25 17 - 26 17 - 27 17 - 28 17 - 29 18 - 2a 18 - 2b 18 - 2c 18 - 2d 18 - 2e 18 - 2f 18 - 30 18 - 31 18 - 34 19 - 35 19 - 36 20 - 39 23 - 3a 23 - 3b 23 - 3c 23 - 3d 23 - 3e 23 - 3f 23 - 40 23 - 44 26 - 45 26 - 46 26 - 47 26 - 48 26 - 49 26 - 4a 27 - 4b 27 - 4c 27 - 4d 27 - 4e 27 - 4f 27 - 50 27 - 51 27 - 55 14 - 56 14 - 57 14 - 58 14 - 59 14 - 5a 14 - 5b 14 - 5c 14 - 60 30 - 61 30 - 62 30 - 63 30 - 64 30 - 65 30 - 66 30 - 67 30 - 6b 15 + 24 15 + 25 15 + 26 15 + 27 15 + 28 15 + 29 16 + 2a 16 + 2b 16 + 2c 16 + 2d 16 + 2e 16 + 2f 16 + 30 16 + 31 16 + 34 17 + 35 17 + 36 18 + 39 21 + 3a 21 + 3b 21 + 3c 21 + 3d 21 + 3e 21 + 3f 21 + 40 21 + 44 24 + 45 24 + 46 24 + 47 24 + 48 24 + 49 24 + 4a 25 + 4b 25 + 4c 25 + 4d 25 + 4e 25 + 4f 25 + 50 25 + 51 25 + 55 12 + 56 12 + 57 12 + 58 12 + 59 12 + 5a 12 + 5b 12 + 5c 12 + 60 28 + 61 28 + 62 28 + 63 28 + 64 28 + 65 28 + 66 28 + 67 28 + 6b 13 } } class 'pkg/TestSwitchPatternMatching2$Triangle' { method 'calculateArea ()D' { - 0 43 - 1 43 + 0 41 + 1 41 } } Lines mapping: 5 <-> 7 -6 <-> 18 -7 <-> 24 -8 <-> 27 -9 <-> 28 -11 <-> 15 -13 <-> 31 -15 <-> 16 -25 <-> 44 +6 <-> 16 +7 <-> 22 +8 <-> 25 +9 <-> 26 +11 <-> 13 +13 <-> 29 +15 <-> 14 +25 <-> 42 diff --git a/testData/results/pkg/TestTextBlocks.dec b/testData/results/pkg/TestTextBlocks.dec index 4feb898be6..65f2c0b315 100644 --- a/testData/results/pkg/TestTextBlocks.dec +++ b/testData/results/pkg/TestTextBlocks.dec @@ -8,9 +8,7 @@ public class TestTextBlocks { }// 20 public void testCall() { - this.useString(// 23 - "Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n" - ); + this.useString("Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n");// 23 }// 30 private void useString(String s) { @@ -28,23 +26,23 @@ class 'pkg/TestTextBlocks' { method 'testCall ()V' { 0 10 - 1 11 - 2 11 + 1 10 + 2 10 3 10 4 10 5 10 - 6 13 + 6 11 } method 'useString (Ljava/lang/String;)V' { - 0 16 - 1 16 - 2 16 - 3 16 - 4 16 - 5 16 - 6 16 - 7 17 + 0 14 + 1 14 + 2 14 + 3 14 + 4 14 + 5 14 + 6 14 + 7 15 } } @@ -52,6 +50,6 @@ Lines mapping: 13 <-> 7 20 <-> 8 23 <-> 11 -30 <-> 14 -33 <-> 17 -34 <-> 18 +30 <-> 12 +33 <-> 15 +34 <-> 16 diff --git a/testData/src/java8/pkg/TestBinaryOperationWrapping.java b/testData/src/java8/pkg/TestBinaryOperationWrapping.java index 9d19d2b2f9..282a3bc120 100644 --- a/testData/src/java8/pkg/TestBinaryOperationWrapping.java +++ b/testData/src/java8/pkg/TestBinaryOperationWrapping.java @@ -8,7 +8,7 @@ public void testStringConcatenation(String longVariableName) { ); } - public void testBooleanOperation(boolean a, boolean b, boolean c, boolean d, boolean e, boolean f, boolean g, boolean h, boolean i, boolean j, boolean k, boolean l, boolean m, boolean n, boolean o, boolean p, boolean q, boolean r, boolean s, boolean t, boolean u, boolean v, boolean w, boolean x, boolean y, boolean z) { - System.out.println(a && b || c && d || e && f || g && h || i && j || k && l || m && n || o && p || q && r || s && t || u && v || w && x || y && z); + public void testBooleanOperation(boolean a, boolean b, boolean c, boolean d, boolean e, boolean f, boolean g, boolean h, boolean i, boolean j, boolean k, boolean l, boolean m, boolean n, boolean o, boolean p, boolean q, boolean r, boolean s, boolean t, boolean u, boolean v, boolean w, boolean x, boolean y, boolean z, boolean a1, boolean b1, boolean c1, boolean d1) { + System.out.println(a && b || c && d || e && f || g && h || i && j || k && l || m && n || o && p || q && r || s && t || u && v || w && x || y && z || a1 && b1 || c1 && d1); } } From 598c5cd0f35c7170bf402798fcbc7e3b66108560 Mon Sep 17 00:00:00 2001 From: ByMartrixx Date: Sun, 21 Nov 2021 21:21:58 -0300 Subject: [PATCH 36/85] Add try with resources nested loop test --- .../java/decompiler/SingleClassesTest.java | 2 + .../pkg/TestTryWithResourcesNestedLoop.dec | 290 ++++++++++++++++++ .../pkg/TestTryWithResourcesNestedLoop.java | 36 +++ 3 files changed, 328 insertions(+) create mode 100644 testData/results/pkg/TestTryWithResourcesNestedLoop.dec create mode 100644 testData/src/java16/pkg/TestTryWithResourcesNestedLoop.java diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 2d22690e53..5a73925c3e 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -479,6 +479,8 @@ private void registerJavaRuntime() { register(JAVA_16, "TestTryWithResourcesLoopJ16"); register(JAVA_16, "TestTryWithResourcesFake"); register(JAVA_16, "TestTryWithResourcesSwitchJ16"); + // TODO: removing the weird edge processing fix in TryWithResourcesProcessor#makeTryWithResourceJ11 produces two returns in a row + register(JAVA_16, "TestTryWithResourcesNestedLoop"); } private void registerLiterals() { diff --git a/testData/results/pkg/TestTryWithResourcesNestedLoop.dec b/testData/results/pkg/TestTryWithResourcesNestedLoop.dec new file mode 100644 index 0000000000..df42caa2b4 --- /dev/null +++ b/testData/results/pkg/TestTryWithResourcesNestedLoop.dec @@ -0,0 +1,290 @@ +package pkg; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +public class TestTryWithResourcesNestedLoop { + public static InputStream test(Path base, Path overlay, int width, int left, int top, int right, int bottom) throws IOException { + InputStream lv = Files.newInputStream(base); + + ByteArrayInputStream var23; + label105: { + try { + InputStream lv2; + label107: { + lv2 = Files.newInputStream(overlay);// 12 + + try { + int n = lv.available();// 14 + int o = lv.read();// 15 + if (n != lv2.available() || o != lv2.read()) {// 17 + break label107; + } + + try (ByteArrayInputStream lv3 = new ByteArrayInputStream(new byte[0], n, o)) {// 18 + int p = n / width;// 19 + + for(int q = top * p; q < bottom * p; ++q) {// 20 + for(int r = left * p; r < right * p; ++r) {// 21 + lv2.read(new byte[0], r, q);// 22 + lv.read(new byte[0], r, q);// 23 + lv3.read(new byte[0], r, q);// 25 + } + } + + var23 = new ByteArrayInputStream(lv3.readAllBytes()); + } + } catch (Throwable var21) { + if (lv2 != null) { + try { + lv2.close(); + } catch (Throwable var18) { + var21.addSuppressed(var18); + } + } + + throw var21; + } + + if (lv2 != null) { + lv2.close(); + } + break label105; + } + + if (lv2 != null) { + lv2.close(); + } + } catch (Throwable var22) {// 11 + if (lv != null) { + try { + lv.close(); + } catch (Throwable var17) { + var22.addSuppressed(var17); + } + } + + throw var22; + } + + if (lv != null) {// 32 + lv.close(); + } + + return null;// 34 + } + + if (lv != null) { + lv.close(); + } + + return var23;// 29 + } +} + +class 'pkg/TestTryWithResourcesNestedLoop' { + method 'test (Ljava/nio/file/Path;Ljava/nio/file/Path;IIIII)Ljava/io/InputStream;' { + 0 10 + 5 10 + 6 10 + 7 10 + 8 10 + 9 10 + a 17 + f 17 + 10 17 + 11 17 + 12 17 + 13 17 + 14 20 + 15 20 + 16 20 + 17 20 + 18 20 + 19 20 + 1a 20 + 1b 21 + 1c 21 + 1d 21 + 1e 21 + 1f 21 + 20 21 + 21 21 + 22 22 + 23 22 + 24 22 + 25 22 + 26 22 + 27 22 + 28 22 + 29 22 + 2c 22 + 2d 22 + 2e 22 + 2f 22 + 30 22 + 31 22 + 32 22 + 33 22 + 3a 26 + 3d 26 + 3e 26 + 3f 26 + 40 26 + 44 26 + 45 26 + 46 27 + 47 27 + 48 27 + 49 27 + 4a 27 + 4b 27 + 4c 29 + 4d 29 + 4e 29 + 4f 29 + 50 29 + 51 29 + 52 29 + 53 29 + 54 29 + 55 29 + 56 29 + 57 29 + 58 29 + 59 29 + 5a 29 + 5d 30 + 5e 30 + 5f 30 + 60 30 + 61 30 + 62 30 + 63 30 + 64 30 + 65 30 + 66 30 + 67 30 + 68 30 + 69 30 + 6a 30 + 6d 31 + 6e 31 + 6f 31 + 72 31 + 73 31 + 74 31 + 75 31 + 76 31 + 77 31 + 78 31 + 7b 32 + 7c 32 + 7d 32 + 80 32 + 81 32 + 82 32 + 83 32 + 84 32 + 85 32 + 86 32 + 89 33 + 8a 33 + 8b 33 + 8e 33 + 8f 33 + 90 33 + 91 33 + 92 33 + 93 33 + 94 33 + 96 30 + 97 30 + 98 30 + 9c 29 + 9d 29 + 9e 29 + a6 37 + a7 37 + a8 37 + a9 37 + aa 37 + ae 37 + af 37 + b5 51 + b6 51 + b7 51 + ba 52 + bb 52 + bc 52 + bf 79 + c0 79 + c1 79 + c4 80 + c5 80 + c6 80 + c9 83 + ca 83 + cb 83 + e2 57 + e3 57 + e4 57 + e7 58 + e8 58 + e9 58 + ea 58 + eb 58 + ef 39 + f1 40 + f2 40 + f3 40 + f6 42 + f7 42 + f8 42 + fe 43 + 104 44 + 109 48 + 10a 72 + 10b 72 + 10c 72 + 10f 73 + 110 73 + 111 73 + 112 73 + 113 73 + 117 60 + 119 61 + 11a 61 + 11b 61 + 11e 63 + 11f 63 + 120 63 + 126 64 + 12c 65 + 131 69 + 132 76 + 133 76 + } +} + +Lines mapping: +11 <-> 61 +12 <-> 18 +14 <-> 21 +15 <-> 22 +17 <-> 23 +18 <-> 27 +19 <-> 28 +20 <-> 30 +21 <-> 31 +22 <-> 32 +23 <-> 33 +25 <-> 34 +29 <-> 84 +32 <-> 73 +34 <-> 77 +Not mapped: +30 diff --git a/testData/src/java16/pkg/TestTryWithResourcesNestedLoop.java b/testData/src/java16/pkg/TestTryWithResourcesNestedLoop.java new file mode 100644 index 0000000000..979adaccc1 --- /dev/null +++ b/testData/src/java16/pkg/TestTryWithResourcesNestedLoop.java @@ -0,0 +1,36 @@ +package pkg; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +public class TestTryWithResourcesNestedLoop { + public static InputStream test(Path base, Path overlay, int width, int left, int top, int right, int bottom) throws IOException { + try (InputStream lv = Files.newInputStream(base); + InputStream lv2 = Files.newInputStream(overlay)) { + + int n = lv.available(); + int o = lv.read(); + + if (n == lv2.available() && o == lv2.read()) { + try (ByteArrayInputStream lv3 = new ByteArrayInputStream(new byte[0], n, o)) { + int p = n / width; + for (int q = top * p; q < bottom * p; q++) { + for (int r = left * p; r < right * p; r++) { + int s = lv2.read(new byte[0], r, q); + int t = lv.read(new byte[0], r, q); + + lv3.read(new byte[0], r, q); + } + } + + return new ByteArrayInputStream(lv3.readAllBytes()); + } + } + } + + return null; + } +} From 4f55c079f2a7b4e7bb093ec2328616b360fe58dd Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Mon, 22 Nov 2021 14:51:37 -0500 Subject: [PATCH 37/85] More tests and docs --- .../decompiler/main/rels/DecompileRecord.java | 4 +- .../modules/decompiler/StatEdge.java | 15 +- .../modules/decompiler/TryHelper.java | 1 + .../decompiler/TryWithResourcesProcessor.java | 1 + .../modules/decompiler/exps/Exprent.java | 2 +- .../java/decompiler/SingleClassesTest.java | 9 +- testData/results/pkg/TestFinallyThrow.dec | 126 ++++++++ .../results/pkg/TestLocalClassesSwitch.dec | 273 ++++++++++++++++++ .../pkg/TestRecordGenericSuperclass.dec | 34 +++ .../pkg/TestRecordGenericSuperclass.java | 13 + testData/src/java8/pkg/TestFinallyThrow.java | 45 +++ .../src/java8/pkg/TestLocalClassesSwitch.java | 88 ++++++ 12 files changed, 605 insertions(+), 6 deletions(-) create mode 100644 testData/results/pkg/TestFinallyThrow.dec create mode 100644 testData/results/pkg/TestLocalClassesSwitch.dec create mode 100644 testData/results/pkg/TestRecordGenericSuperclass.dec create mode 100644 testData/src/java16/pkg/TestRecordGenericSuperclass.java create mode 100644 testData/src/java8/pkg/TestFinallyThrow.java create mode 100644 testData/src/java8/pkg/TestLocalClassesSwitch.java diff --git a/src/org/jetbrains/java/decompiler/main/rels/DecompileRecord.java b/src/org/jetbrains/java/decompiler/main/rels/DecompileRecord.java index e8619ceeeb..61abc68786 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/DecompileRecord.java +++ b/src/org/jetbrains/java/decompiler/main/rels/DecompileRecord.java @@ -59,8 +59,8 @@ public List getNames() { } public void print() { - for (String name : this.names) { - System.out.println(name); + for (int i = 0; i < this.names.size(); i++) { + System.out.println(i + " " + this.names.get(0)); } } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java b/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java index 30717a5488..3caf36b5e9 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java @@ -38,6 +38,19 @@ public class StatEdge { private List exceptions; + // The statement that this edge is enclosed in. + // Take for example, this structure, where we are analyzing the break edge: + // + // label1: { + // if (...) { + // break label1; + // } + // } + // System.out.println("Test"); + // + // The body of the if statement would be considered the source, and the println would be considered the destination. + // The sequence statement enclosing the if would be considered the closure. + // BREAK and CONTINUE edge types should always have a closure! (except for when break edges are return edges) public Statement closure; // Whether this edge is labeled or not. @@ -46,7 +59,7 @@ public class StatEdge { // Whether this edge is explicitly defined or implicit. public boolean explicit = true; - // Whether this edge can be inlined to simplify the decompile or not. + // Whether this edge can be inlined to simplify the decompiled output or not. public boolean canInline = true; public StatEdge(int type, Statement source, Statement destination, Statement closure) { diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java index 422544021e..42d22343de 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java @@ -37,6 +37,7 @@ public static boolean enhanceTryStats(RootStatement root, StructClass cl) { } private static boolean makeTryWithResourceRec(StructClass cl, Statement stat) { + // TODO: new try with resources *reruns the entire processing loop after a single one is run.* That is not efficient and could be optimized if (cl.getVersion().hasNewTryWithResources()) { if (stat.type == Statement.TYPE_TRYCATCH) { if (TryWithResourcesProcessor.makeTryWithResourceJ11((CatchStatement) stat)) { diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java index dbeda35b5c..3e5c678096 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java @@ -276,6 +276,7 @@ public static boolean makeTryWithResourceJ11(CatchStatement tryStatement) { // When the predecessor is the try statement, we add normal control flow, as the successor is located next to the try statement. When it is not, it must be inside the try, so we break out of it. // This prevents successor blocks from being inlined, as there are still multiple breaks to the successor and not a singular one that can be inlined [TestTryWithResourcesCatchJ16#test1] + // TODO: break closure? StatEdge newEdge = new StatEdge(predStat == tryStatement ? StatEdge.TYPE_REGULAR : StatEdge.TYPE_BREAK, predStat, successor.getDestination()); predStat.addSuccessor(newEdge); } 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 307eae4f5d..07edb5a468 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java @@ -97,7 +97,7 @@ public boolean containsExprent(Exprent exprent) { return false; } - public List getAllExprents(boolean recursive) { + public final List getAllExprents(boolean recursive) { List lst = new ArrayList<>(); getAllExprents(recursive, lst); diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 2d22690e53..0036131d74 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -209,6 +209,7 @@ private void registerDefault() { register(JAVA_16, "TestRecordGenericVararg"); register(JAVA_16, "TestRecordAnno"); register(JAVA_16, "TestRecordBig"); + register(JAVA_16, "TestRecordGenericSuperclass"); // TODO: The (double) in front of the (int) should be removed register(JAVA_8, "TestMultiCast"); // TODO: The ternary here needs to be removed @@ -427,13 +428,17 @@ private void registerDefault() { // TODO: Synchronized blocks don't work properly registerRaw(CUSTOM, "TestHotjava"); register(JAVA_8, "TestLabeledBreaks"); + // TODO: test6&7- for loop processing leaves empty switch default edge + // TODO: test9&10- for loop not created, loop extractor needs another pass register(JAVA_8, "TestSwitchLoop"); // TODO: finally block is duplicating the switches, FinallyProcessor#verifyFinallyEx not correct register(JAVA_8, "TestSwitchFinally"); // TODO: test2- continue not explicit, causes improper control flow - // TODO: test6&7- for loop processing leaves empty switch default edge - // TODO: test9&10- for loop not created, loop extractor needs another pass register(JAVA_8, "TestLoopFinally"); + // TODO: local classes not being put in the right spots + register(JAVA_8, "TestLocalClassesSwitch"); // Adapted from CFR + // TODO: return not condensed properly and throw is not put into finally + register(JAVA_8, "TestFinallyThrow"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestFinallyThrow.dec b/testData/results/pkg/TestFinallyThrow.dec new file mode 100644 index 0000000000..2627ca0734 --- /dev/null +++ b/testData/results/pkg/TestFinallyThrow.dec @@ -0,0 +1,126 @@ +package pkg; + +public class TestFinallyThrow { + public void test(boolean b) { + while(true) { + try { + System.out.println(1);// 7 + } finally { + label127: { + try { + if (!b) {// 10 + break label127; + } + } catch (Exception var22) {// 13 + throw var22;// 14 + } finally { + System.out.println(2);// 16 + } + + return;// 11 + } + + } + } + } + + public void test1(RuntimeException t) { + try { + System.out.println(1);// 24 + throw t; + } catch (Throwable var6) {// 25 + var6.printStackTrace();// 26 + } finally { + ; + } + + throw t;// 28 + } + + public void test2(RuntimeException t) { + try { + System.out.println(1);// 35 + throw t;// 36 + } catch (Throwable var6) {// 37 + var6.printStackTrace();// 38 + } finally { + ; + } + + throw t;// 43 + } +} + +class 'pkg/TestFinallyThrow' { + method 'test (Z)V' { + 0 6 + 1 6 + 2 6 + 3 6 + 4 6 + 2f 10 + 30 10 + 3a 19 + 45 13 + 49 14 + 4a 16 + 4b 16 + 4c 16 + 4d 16 + 4e 16 + 4f 16 + } + + method 'test1 (Ljava/lang/RuntimeException;)V' { + 0 28 + 1 28 + 2 28 + 3 28 + 4 28 + 7 29 + 8 29 + 9 30 + b 31 + e 36 + f 36 + } + + method 'test2 (Ljava/lang/RuntimeException;)V' { + 0 41 + 1 41 + 2 41 + 3 41 + 4 41 + 5 41 + 6 41 + 7 42 + 8 42 + 9 43 + b 44 + 14 49 + 15 49 + } +} + +Lines mapping: +7 <-> 7 +10 <-> 11 +11 <-> 20 +13 <-> 14 +14 <-> 15 +16 <-> 17 +24 <-> 29 +25 <-> 31 +26 <-> 32 +28 <-> 37 +35 <-> 42 +36 <-> 43 +37 <-> 44 +38 <-> 45 +43 <-> 50 +Not mapped: +9 +17 +18 +39 +41 diff --git a/testData/results/pkg/TestLocalClassesSwitch.dec b/testData/results/pkg/TestLocalClassesSwitch.dec new file mode 100644 index 0000000000..e11f12409c --- /dev/null +++ b/testData/results/pkg/TestLocalClassesSwitch.dec @@ -0,0 +1,273 @@ +package pkg; + +public class TestLocalClassesSwitch { + public void test(int i) { + switch(i) {// 6 + case 0: + class LocalClass { + public void test() { + System.out.println("test");// 10 + }// 11 + } + + LocalClass lc = new LocalClass();// 14 + lc.test();// 15 + default: + class LocalClass { + public void test() { + System.out.println("test1");// 21 + }// 22 + } + + LocalClass lc = new LocalClass();// 25 + lc.test();// 26 + } + }// 27 + + public void test1(int i) { + switch(i) {// 30 + case 0: + class LocalClass { + public void test() { + System.out.println("test");// 34 + }// 35 + } + + LocalClass lc = new LocalClass();// 38 + lc.test();// 39 + break;// 40 + case 1: + class LocalClass { + public void test() { + System.out.println("test1");// 45 + }// 46 + } + + LocalClass lc = new LocalClass();// 49 + lc.test();// 50 + } + + class LocalClass { + public void test() { + System.out.println("test2");// 57 + }// 58 + } + + LocalClass lc = new LocalClass();// 61 + lc.test();// 62 + }// 63 + + public void test2(int i) { + switch(i) {// 66 + default: + class LocalClass { + public void test() { + System.out.println("test");// 70 + }// 71 + } + + LocalClass lc = new LocalClass();// 74 + lc.test();// 75 + + class LocalClass { + public void test() { + System.out.println("test1");// 81 + }// 82 + } + + LocalClass lc = new LocalClass();// 85 + lc.test();// 86 + } + }// 87 +} + +class 'pkg/TestLocalClassesSwitch' { + method 'test (I)V' { + 0 4 + 1 4 + 1c 12 + 1d 13 + 1e 13 + 29 21 + 2a 22 + 2b 22 + 2c 22 + 2d 22 + 2e 24 + } + + method 'test1 (I)V' { + 0 27 + 1 27 + 24 35 + 25 36 + 26 36 + 27 36 + 28 36 + 29 37 + 34 45 + 35 46 + 36 46 + 37 46 + 38 46 + 44 55 + 45 56 + 46 56 + 47 56 + 48 56 + 49 57 + } + + method 'test2 (I)V' { + 0 60 + 1 60 + 14 68 + 15 69 + 16 69 + 17 69 + 18 69 + 21 77 + 22 78 + 23 78 + 24 78 + 25 78 + 26 80 + } +} + +class 'pkg/TestLocalClassesSwitch$1LocalClass' { + method 'test ()V' { + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 8 + 6 8 + 7 8 + 8 9 + } +} + +class 'pkg/TestLocalClassesSwitch$2LocalClass' { + method 'test ()V' { + 0 17 + 1 17 + 2 17 + 3 17 + 4 17 + 5 17 + 6 17 + 7 17 + 8 18 + } +} + +class 'pkg/TestLocalClassesSwitch$3LocalClass' { + method 'test ()V' { + 0 31 + 1 31 + 2 31 + 3 31 + 4 31 + 5 31 + 6 31 + 7 31 + 8 32 + } +} + +class 'pkg/TestLocalClassesSwitch$4LocalClass' { + method 'test ()V' { + 0 41 + 1 41 + 2 41 + 3 41 + 4 41 + 5 41 + 6 41 + 7 41 + 8 42 + } +} + +class 'pkg/TestLocalClassesSwitch$5LocalClass' { + method 'test ()V' { + 0 51 + 1 51 + 2 51 + 3 51 + 4 51 + 5 51 + 6 51 + 7 51 + 8 52 + } +} + +class 'pkg/TestLocalClassesSwitch$6LocalClass' { + method 'test ()V' { + 0 64 + 1 64 + 2 64 + 3 64 + 4 64 + 5 64 + 6 64 + 7 64 + 8 65 + } +} + +class 'pkg/TestLocalClassesSwitch$7LocalClass' { + method 'test ()V' { + 0 73 + 1 73 + 2 73 + 3 73 + 4 73 + 5 73 + 6 73 + 7 73 + 8 74 + } +} + +Lines mapping: +6 <-> 5 +10 <-> 9 +11 <-> 10 +14 <-> 13 +15 <-> 14 +21 <-> 18 +22 <-> 19 +25 <-> 22 +26 <-> 23 +27 <-> 25 +30 <-> 28 +34 <-> 32 +35 <-> 33 +38 <-> 36 +39 <-> 37 +40 <-> 38 +45 <-> 42 +46 <-> 43 +49 <-> 46 +50 <-> 47 +57 <-> 52 +58 <-> 53 +61 <-> 56 +62 <-> 57 +63 <-> 58 +66 <-> 61 +70 <-> 65 +71 <-> 66 +74 <-> 69 +75 <-> 70 +81 <-> 74 +82 <-> 75 +85 <-> 78 +86 <-> 79 +87 <-> 81 +Not mapped: +51 diff --git a/testData/results/pkg/TestRecordGenericSuperclass.dec b/testData/results/pkg/TestRecordGenericSuperclass.dec new file mode 100644 index 0000000000..9a3fb061f8 --- /dev/null +++ b/testData/results/pkg/TestRecordGenericSuperclass.dec @@ -0,0 +1,34 @@ +package pkg; + +public class TestRecordGenericSuperclass { + public G getNum() { + return (G)null;// 5 + } + + public static record Rec(G num) { + public G getNum() { + return this.num;// 10 + } + } +} + +class 'pkg/TestRecordGenericSuperclass' { + method 'getNum ()Ljava/lang/Number;' { + 0 4 + 1 4 + } +} + +class 'pkg/TestRecordGenericSuperclass$Rec' { + method 'getNum ()Ljava/lang/Object;' { + 0 9 + 1 9 + 2 9 + 3 9 + 4 9 + } +} + +Lines mapping: +5 <-> 5 +10 <-> 10 diff --git a/testData/src/java16/pkg/TestRecordGenericSuperclass.java b/testData/src/java16/pkg/TestRecordGenericSuperclass.java new file mode 100644 index 0000000000..68494acccc --- /dev/null +++ b/testData/src/java16/pkg/TestRecordGenericSuperclass.java @@ -0,0 +1,13 @@ +package pkg; + +public class TestRecordGenericSuperclass { + public G getNum() { + return null; + } + + public record Rec(G num) { + public G getNum() { + return this.num; + } + } +} diff --git a/testData/src/java8/pkg/TestFinallyThrow.java b/testData/src/java8/pkg/TestFinallyThrow.java new file mode 100644 index 0000000000..af20bf29f2 --- /dev/null +++ b/testData/src/java8/pkg/TestFinallyThrow.java @@ -0,0 +1,45 @@ +package pkg; + +public class TestFinallyThrow { + public void test(boolean b) { + while (true) { + try { + System.out.println(1); + } finally { + try { + if (b) { + return; + } + } catch (Exception e) { + throw e; + } finally { + System.out.println(2); + } + } + } + } + + public void test1(RuntimeException t) { + try { + System.out.println(1); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + throw t; + } + } + + // test1 decompiles as this: + public void test2(RuntimeException t) { + try { + System.out.println(1); + throw t; + } catch (Throwable e) { + e.printStackTrace(); + } finally { + + } + + throw t; + } +} diff --git a/testData/src/java8/pkg/TestLocalClassesSwitch.java b/testData/src/java8/pkg/TestLocalClassesSwitch.java new file mode 100644 index 0000000000..6ac5f8ee3f --- /dev/null +++ b/testData/src/java8/pkg/TestLocalClassesSwitch.java @@ -0,0 +1,88 @@ +package pkg; + +// Adapted from CFR +public class TestLocalClassesSwitch { + public void test(int i) { + switch (i) { + case 0: + class LocalClass { + public void test() { + System.out.println("test"); + } + } + + LocalClass lc = new LocalClass(); + lc.test(); + break; + } + + class LocalClass { + public void test() { + System.out.println("test1"); + } + } + + LocalClass lc = new LocalClass(); + lc.test(); + } + + public void test1(int i) { + switch (i) { + case 0: { + class LocalClass { + public void test() { + System.out.println("test"); + } + } + + LocalClass lc = new LocalClass(); + lc.test(); + break; + } + case 1: { + class LocalClass { + public void test() { + System.out.println("test1"); + } + } + + LocalClass lc = new LocalClass(); + lc.test(); + break; + } + } + + class LocalClass { + public void test() { + System.out.println("test2"); + } + } + + LocalClass lc = new LocalClass(); + lc.test(); + } + + public void test2(int i) { + switch (i) { + default: + class LocalClass { + public void test() { + System.out.println("test"); + } + } + + LocalClass lc = new LocalClass(); + lc.test(); + break; + } + + class LocalClass { + public void test() { + System.out.println("test1"); + } + } + + LocalClass lc = new LocalClass(); + lc.test(); + } +} From 192e07c1661a98245a2316a56bd844e31b2285ee Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Mon, 22 Nov 2021 15:10:02 -0500 Subject: [PATCH 38/85] Don't append deprecated javadoc when deprecated annotation exists --- .../java/decompiler/main/ClassWriter.java | 27 ++++++++++-- testData/results/pkg/TestDeprecations.dec | 44 +++++++++---------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 6f24e5c1d6..b9cbb1aa51 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -439,7 +439,9 @@ private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) boolean isNonSealed = !isSealed && cl.getVersion().hasSealedClasses() && isSuperClassSealed(cl); if (isDeprecated) { - appendDeprecation(buffer, indent); + if (!containsDeprecatedAnnotation(cl)) { + appendDeprecation(buffer, indent); + } } if (interceptor != null) { @@ -587,7 +589,9 @@ private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, T boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); if (isDeprecated) { - appendDeprecation(buffer, indent); + if (!containsDeprecatedAnnotation(fd)) { + appendDeprecation(buffer, indent); + } } if (interceptor != null) { @@ -795,7 +799,9 @@ private boolean methodToJava(ClassNode node, StructMethod mt, int methodIndex, T } if (isDeprecated) { - appendDeprecation(buffer, indent); + if (!containsDeprecatedAnnotation(mt)) { + appendDeprecation(buffer, indent); + } } if (interceptor != null) { @@ -1263,6 +1269,21 @@ private static Map.Entry getFieldTypeData(Struc return new AbstractMap.SimpleImmutableEntry<>(fieldType, descriptor); } + private static boolean containsDeprecatedAnnotation(StructMember mb) { + for (StructGeneralAttribute.Key key : ANNOTATION_ATTRIBUTES) { + StructAnnotationAttribute attribute = (StructAnnotationAttribute) mb.getAttribute(key); + if (attribute != null) { + for (AnnotationExprent annotation : attribute.getAnnotations()) { + if (annotation.getClassName().equals("java/lang/Deprecated")) { + return true; + } + } + } + } + + return false; + } + private static void appendDeprecation(TextBuffer buffer, int indent) { buffer.appendIndent(indent).append("/** @deprecated */").appendLineSeparator(); } diff --git a/testData/results/pkg/TestDeprecations.dec b/testData/results/pkg/TestDeprecations.dec index 6b7dcec272..567d1c032a 100644 --- a/testData/results/pkg/TestDeprecations.dec +++ b/testData/results/pkg/TestDeprecations.dec @@ -3,7 +3,6 @@ package pkg; public abstract class TestDeprecations { /** @deprecated */ public int byComment; - /** @deprecated */ @Deprecated public int byAnno; @@ -15,17 +14,14 @@ public abstract class TestDeprecations { /** @deprecated */ public abstract void byCommentAbstract(); - /** @deprecated */ @Deprecated public void byAnno() { int a = 5;// 35 }// 36 - /** @deprecated */ @Deprecated public abstract void byAnnoAbstract(); - /** @deprecated */ @Deprecated public static class ByAnno { int a = 5; @@ -47,40 +43,40 @@ public abstract class TestDeprecations { class 'pkg/TestDeprecations' { method 'byComment ()V' { - 0 11 - 1 11 - 2 12 + 0 10 + 1 10 + 2 11 } method 'byAnno ()V' { - 0 20 - 1 20 - 2 21 + 0 18 + 1 18 + 2 19 } } class 'pkg/TestDeprecations$ByAnno' { method 'foo ()V' { - 0 33 - 1 33 - 2 34 + 0 29 + 1 29 + 2 30 } } class 'pkg/TestDeprecations$ByComment' { method 'foo ()V' { - 0 42 - 1 42 - 2 43 + 0 38 + 1 38 + 2 39 } } Lines mapping: -27 <-> 12 -28 <-> 13 -35 <-> 21 -36 <-> 22 -46 <-> 43 -47 <-> 44 -55 <-> 34 -56 <-> 35 +27 <-> 11 +28 <-> 12 +35 <-> 19 +36 <-> 20 +46 <-> 39 +47 <-> 40 +55 <-> 30 +56 <-> 31 From 66db1eee08e4fc497ed794a50a05a9dc531fcd45 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Mon, 22 Nov 2021 18:45:46 -0500 Subject: [PATCH 39/85] Make do while rerun the method processing loop, improve empty for loop detection --- .../main/rels/MethodProcessorRunnable.java | 7 +- .../modules/decompiler/MergeHelper.java | 23 ++++--- .../java/decompiler/SingleClassesTest.java | 1 + testData/results/pkg/TestClassVar.dec | 54 +++++++-------- testData/results/pkg/TestWhile1.dec | 66 +++++++++++++++++++ testData/src/java8/pkg/TestWhile1.java | 18 +++++ 6 files changed, 129 insertions(+), 40 deletions(-) create mode 100644 testData/results/pkg/TestWhile1.dec create mode 100644 testData/src/java8/pkg/TestWhile1.java diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java index bba0f9b148..d70259cdeb 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java +++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java @@ -275,12 +275,7 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe // this has to be done last so it does not screw up the formation of for loops if (MergeHelper.makeDoWhileLoops(root)) { decompileRecord.add("MatchDoWhile", root); - - LabelHelper.cleanUpEdges(root); - decompileRecord.add("CleanupEdges_MDW", root); - - LabelHelper.identifyLabels(root); - decompileRecord.add("IdentifyLabels_MDW", root); + continue; } // initializer may have at most one return point, so no transformation of method exits permitted diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java index abd3245d37..ce32022557 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java @@ -488,16 +488,23 @@ private static void matchFor(DoStatement stat) { // Break out of the loop if we find that the third assignment is the only expression in the basic block. // First filter to make sure that the loop body (includes the last assignment) has a single statement. - if (stat.getFirst().getStats().size() == 1) { - Statement firstStat = stat.getFirst().getStats().get(0); - // Then filter to make sure the loop body is a basic block (Seems like it always is- but it never hurts to double check!) - if (firstStat.type == Statement.TYPE_BASICBLOCK) { + Statement firstStat = stat.getFirst(); + while (firstStat.type == Statement.TYPE_SEQUENCE && firstStat.getStats().size() == 1) { + Statement fst = firstStat.getFirst(); + if (fst == null) { + break; + } - // Last filter to make sure the basic block only has the final third assignment. If so, break out to make a while loop instead as it will produce cleaner output. - if (firstStat.getExprents().size() == 1) { - return; - } + firstStat = fst; + } + + // Then filter to make sure the loop body is a basic block (Seems like it always is- but it never hurts to double check!) + if (firstStat.type == Statement.TYPE_BASICBLOCK) { + + // Last filter to make sure the basic block only has the final third assignment. If so, break out to make a while loop instead as it will produce cleaner output. + if (firstStat.getExprents().size() == 1) { + return; } } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 517d859557..dabb402da5 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -439,6 +439,7 @@ private void registerDefault() { register(JAVA_8, "TestLocalClassesSwitch"); // Adapted from CFR // TODO: return not condensed properly and throw is not put into finally register(JAVA_8, "TestFinallyThrow"); + register(JAVA_8, "TestWhile1"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestClassVar.dec b/testData/results/pkg/TestClassVar.dec index e4266cc495..a3803b162e 100644 --- a/testData/results/pkg/TestClassVar.dec +++ b/testData/results/pkg/TestClassVar.dec @@ -26,8 +26,10 @@ public class TestClassVar { int a = 0;// 45 while(a < 10) {// 47 - int b; - for(b = a; a < 10 && a == 0; ++a) {// 49 51 + int b = a;// 49 + + while(a < 10 && a == 0) {// 51 + ++a; } if (b != a) {// 54 @@ -80,25 +82,25 @@ class 'pkg/TestClassVar' { 3 27 4 27 5 27 - 8 29 - 9 29 - a 29 - b 29 - c 29 - d 29 - 10 29 - 11 29 - 14 29 - 15 29 - 16 29 - 1a 32 - 1b 32 - 1c 32 - 1f 33 - 20 33 - 21 33 - 22 33 - 28 37 + 8 28 + 9 28 + a 30 + b 30 + c 30 + d 30 + 10 30 + 11 30 + 14 31 + 15 31 + 16 31 + 1a 34 + 1b 34 + 1c 34 + 1f 35 + 20 35 + 21 35 + 22 35 + 28 39 } } @@ -111,11 +113,11 @@ Lines mapping: 40 <-> 22 45 <-> 26 47 <-> 28 -49 <-> 30 -51 <-> 30 -54 <-> 33 -55 <-> 34 -58 <-> 38 +49 <-> 29 +51 <-> 31 +54 <-> 35 +55 <-> 36 +58 <-> 40 Not mapped: 35 57 diff --git a/testData/results/pkg/TestWhile1.dec b/testData/results/pkg/TestWhile1.dec new file mode 100644 index 0000000000..c76935b521 --- /dev/null +++ b/testData/results/pkg/TestWhile1.dec @@ -0,0 +1,66 @@ +package pkg; + +public class TestWhile1 { + public void test(double a, double g) { + while(a > 0.0) {// 5 + a -= 2.0;// 6 + } + + double d = g;// 9 + + while(d >= 3.0) {// 10 + d -= 2.0;// 11 + } + + while(d <= 0.0) {// 14 + d += 2.0;// 15 + } + + }// 17 +} + +class 'pkg/TestWhile1' { + method 'test (DD)V' { + 0 4 + 1 4 + 2 4 + 7 5 + 8 5 + 9 5 + b 5 + f 8 + 10 8 + 11 8 + 12 10 + 13 10 + 14 10 + 15 10 + 16 10 + 17 10 + 1d 11 + 1e 11 + 1f 11 + 21 11 + 22 11 + 26 14 + 27 14 + 28 14 + 29 14 + 2f 15 + 30 15 + 31 15 + 33 15 + 34 15 + 38 18 + } +} + +Lines mapping: +5 <-> 5 +6 <-> 6 +9 <-> 9 +10 <-> 11 +11 <-> 12 +14 <-> 15 +15 <-> 16 +17 <-> 19 diff --git a/testData/src/java8/pkg/TestWhile1.java b/testData/src/java8/pkg/TestWhile1.java new file mode 100644 index 0000000000..2d2a4246c8 --- /dev/null +++ b/testData/src/java8/pkg/TestWhile1.java @@ -0,0 +1,18 @@ +package pkg; + +public class TestWhile1 { + public void test(double a, double g) { + while (a > 0) { + a -= 2; + } + + double d = g; + while (d >= 3) { + d -= 2; + } + + while (d <= 0) { + d += 2; + } + } +} From 248a50cbe8a6354f5ad84c5485b19dd50933abc1 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 23 Nov 2021 08:30:21 -0500 Subject: [PATCH 40/85] Cleanup and documentation --- .../modules/decompiler/ExitHelper.java | 21 ++++++++++++++++++- .../modules/decompiler/SequenceHelper.java | 1 - 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java index 2c57142564..e8d0ab3b41 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java @@ -61,7 +61,25 @@ private static void cleanUpUnreachableBlocks(Statement stat) { while (found); } - // Turns break edges into returns where necessary + // Turns break edges into returns where possible. + // + // Example: + // + // label1: { + // if (...) { + // break label1; + // } + // ... + // } + // return; + // + // will turn into + // + // if (...) { + // return; + // } + // ... + // private static int integrateExits(Statement stat) { int ret = 0; Statement dest; @@ -210,6 +228,7 @@ private static boolean isOnlyEdge(StatEdge edge) { return true; } + // Removes return statements from the ends of methods when they aren't returning a value public static boolean removeRedundantReturns(RootStatement root) { boolean res = false; DummyExitStatement dummyExit = root.getDummyExit(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java index a563c7e528..b3bb7904ea 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java @@ -311,7 +311,6 @@ public static void destroyStatementContent(Statement stat, boolean self) { if (self) { for (StatEdge edge : stat.getAllSuccessorEdges()) { stat.removeSuccessor(edge); - edge.getDestination().removePredecessor(edge); // TODO: this is redundant but is still needed because of null destinations in removeSuccessor? } } } From ad7914616e48ff3df6d175c29af02da4459edaf9 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 23 Nov 2021 11:05:53 -0500 Subject: [PATCH 41/85] Make IdeaNotNullHelper work properly --- .../modules/decompiler/IdeaNotNullHelper.java | 44 ++- .../modules/decompiler/TernaryProcessor.java | 2 - testData/classes/custom/TestIdeaNotNull.class | Bin 2120 -> 3676 bytes testData/results/TestIdeaNotNull.dec | 255 ++++++++++++++---- 4 files changed, 233 insertions(+), 68 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java index ff45d29ef8..277302df68 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java @@ -2,7 +2,11 @@ package org.jetbrains.java.decompiler.modules.decompiler; import org.jetbrains.java.decompiler.code.CodeConstants; +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.exps.*; +import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; @@ -12,6 +16,7 @@ import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; +import java.util.ArrayList; import java.util.List; public final class IdeaNotNullHelper { @@ -56,7 +61,7 @@ private static boolean findAndRemoveParameterCheck(Statement stat, StructMethod ((FunctionExprent)if_condition).getFuncType() == FunctionExprent.FUNCTION_EQ && ifbranch.type == Statement.TYPE_BASICBLOCK && ifbranch.getExprents().size() == 1 && - ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) { + ifbranch.getExprents().get(0).type == Exprent.EXPRENT_INVOCATION) { FunctionExprent func = (FunctionExprent)if_condition; Exprent first_param = func.getLstOperands().get(0); @@ -64,7 +69,7 @@ private static boolean findAndRemoveParameterCheck(Statement stat, StructMethod if (second_param.type == Exprent.EXPRENT_CONST && second_param.getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order - if (first_param.type == Exprent.EXPRENT_VAR) { + if (first_param.type == Exprent.EXPRENT_VAR && ((InvocationExprent)ifbranch.getExprents().get(0)).getName().equals("$$$reportNull$$$0")) { VarExprent var = (VarExprent)first_param; boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC); @@ -129,25 +134,35 @@ private static void removeParameterCheck(Statement stat) { IfStatement ifstat = (IfStatement)st; - if (ifstat.getElsestat() != null) { // if - else + // In the format of + // + // if (param == null) { + // $$$reportNull$$$(index); // index is the index of reportNull appearing in the code + // } + // + if (ifstat.getElsestat() == null) { StatEdge ifedge = ifstat.getIfEdge(); - StatEdge elseedge = ifstat.getElseEdge(); Statement ifbranch = ifstat.getIfstat(); - Statement elsebranch = ifstat.getElsestat(); ifstat.getFirst().removeSuccessor(ifedge); - ifstat.getFirst().removeSuccessor(elseedge); ifstat.getStats().removeWithKey(ifbranch.id); - ifstat.getStats().removeWithKey(elsebranch.id); if (!ifbranch.getAllSuccessorEdges().isEmpty()) { ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0)); } - ifstat.getParent().replaceStatement(ifstat, elsebranch); + // Replace statement with empty block + BasicBlockStatement block = new BasicBlockStatement(new BasicBlock( + DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER))); + block.setExprents(new ArrayList<>()); + + ifstat.getParent().replaceStatement(ifstat, block); ifstat.getParent().setAllParent(); + + // Remove the empty block that we just inserted + SequenceHelper.condenseSequences(stat.getTopParent()); } } @@ -176,6 +191,7 @@ private static boolean removeReturnCheck(Statement stat, StructMethod mt) { Statement parent = stat.getParent(); + // TODO: is this check doing anything? seems like modern notnull creation doesn't cause this to be run. if (parent != null && parent.type == Statement.TYPE_IF && stat.type == Statement.TYPE_BASICBLOCK && stat.getExprents().size() == 1) { Exprent exprent = stat.getExprents().get(0); if (exprent.type == Exprent.EXPRENT_EXIT) { @@ -270,8 +286,16 @@ else if (parent != null && if (first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc. if (ifbranch.type == Statement.TYPE_BASICBLOCK && ifbranch.getExprents().size() == 1 && - // TODO: special check for IllegalStateException - ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) { + ifbranch.getExprents().get(0).type == Exprent.EXPRENT_INVOCATION && ((InvocationExprent)ifbranch.getExprents().get(0)).getName().equals("$$$reportNull$$$0")) { + + // In the format of + // + // if (returnValue == null) { + // $$$reportNull$$$(index); // index is the index of reportNull appearing in the code + // } + // + // return returnValue; + // ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0)); // remove 'else' edge diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TernaryProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TernaryProcessor.java index 33213020c5..dffff15ba8 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TernaryProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TernaryProcessor.java @@ -174,8 +174,6 @@ private static boolean processIf(IfStatement statement) { Statement blockBefore = bstat1.getAllPredecessorEdges().get(0).getSource(); - DotExporter.toDotFile(statement.getTopParent(), "a"+statement.id); - bstat1.getParent().getStats().removeWithKey(bstat1.id); bstat2.getParent().getStats().removeWithKey(bstat2.id); diff --git a/testData/classes/custom/TestIdeaNotNull.class b/testData/classes/custom/TestIdeaNotNull.class index 5e097870f362f2f49903289ebbf087d879cd9e01..ca2108738502834f16de5ab8c3bf88ac8d0cda7a 100644 GIT binary patch literal 3676 zcmb_fOH&kA7(I7h-82IXgMty1Q6M0QBfb$u@IgQad_YLhB&LBD8)v%5o*tuBS>{)m zT^6A#t0W7wLM2&Rl})Ph6H=9R_DM=|Zg0SUta$36Mz$V ztf2*`RGe0DMnf2Mhf!S6Fotp2UDR+1mla&m(1Z!8@ScK6 z1ycgCbEajwqXOZ+L-PWWOZKuM(3CMPW2Tr}G@LnoG0T-?#$M91^SWcod9WC9@0$gI z-I@G@mGqoZaHp0Hea3cYirMT4jk#PB*wuF^v#LMR(^=hGNzb~DX{~Tqtg;b-poL^j z1yi75*439DOzU~?Mg>;|+HVyt*UTAH)+4iE63n<|*{<%Iwna-_8QWP&uNv;6qnlPC ztyebF6=a>;ZOlE%Z?zMZ*oVliZznYAsP63+Zs?AlGhD;j0>?9ROrWoZnJU9mmTRmS z&WNF_`eydvN4ghb=R{j?g=#S*a>W(2;@nD-s(Hb(5eoWW2nvAMQ6#F zFlCDD+Li%FWYFW-h1~)WNO(C=bj@t~mToQExj3#NBha=zH!c>J$dR|{# zHI|sPKH92`6;LeWu}gO_vHPYD$=cELdBa*37_4?!;GCT~AMj%8ckuiUcUHDl*Y=HU zh4G}|8aWoKT_l9v{&~|*-(Wqt)Hn1TO}BV{*t$&Ud8w4Ow&k-=*2|6NivNO$3#dFZ zuV;&lEnf!`-omqV_%%eDySuv`BX2w2i@?cI-*@wI+`&g0lK5Dle=MlW6wBwny`1VP z9O)^fa>at1VqvEo!!0^i%Ho@%;;z8xxU*8s8J3&6XFI9#;e4t7QoTKe-jscByPZWN zu%WA%RMDy8fQqz=b`{4|^s4ArG033OYEGwzYgO8vDzdNSKN3e4ISpN)zdNh^n#~$3 zdX_JmYm}2yL0-c{Ob8s@p;;nYrCiY9O68UsNEAH60s6Fsp9?@`$+7gE8rdM<&5tvI{1N+hkvDZgmN+&%4{IK@C=bed>zsA9Z%6P zu$15I_lP;WxfcDwaq^~&4|>btuPL<--qZXyRd?! zf-XX2kAEPO|il2IGNTN$-7o+Zb(FnWRGePVt;R8IS^X+_c- z-k$bvO7smhEet$E;%6TA6Qv%Zmwt*185xjajJX3^0_%{l6xC%-X9cN`;>`L_tpZDE@}t9;b2Icevy4eD{@nWwIe-ZKpB9Ye zeC#z%?vErtU4xojTtnEiGR!sklQ!g7w)3xPo=$X)1x^b;q9uSr-}paiM~-E?9JEZ8 zoa0!|J)MPca%pxA?Uc)uEtCdjJ>@-0A7O2tmuTZv?Hc#4Eku$lp3R7NM?L5F-(Yi; z=O%(SLs@F`9DBZ7L)StyY0^wP<*H{sntVW6&$(y*IqX;Zwd9Xl((~&E9^StD49*%F zH{i-)kzSA$$uBMYzp&?Ag#QwCJzu`_ ze}$J`m>I9s3+TwGm(Fw?`7AT;%=@1AocH5A@5k9c{`vV=0N3$MM?1ze zjH{T?p6x}u&6>;wDlQGs`SB}St zN$ghzdd5#flNHOHjId&QX4&#B?-(3?&8>Mw>%J|E*?po!)3PcFbRa1Jfn-pmns1k~ ztERK%mJ|38Hw5}l7VmD&F0tkb+{BDzA0;r0J{7kTxQ#g#A181JBLeC3`g3q!(3D4; zJ64gc3LzZnlYr`2ul$@tWpq3@!G6WfO2u-v1TLRdnp4$kf@Qs# z`c|29>edLMC-k@7>aF3>}V5u2izN%@W^|Z!NwmS{3` z(2G9)@uc&gw2pFJN=5SfPzrm9CKJ1e-A;dlwyDDJP?a~h_k%Jwkp33weZ*;@PVGWV z@1kWFdj4xg)Ej>VmQiWRSPBNn2M}wJDJt4j3=$$a{)P|(OHz^$hoO)&kMX#UN!! zs%#85NnO4a%B;B9LyQv8=>MJ^gdctqj+7-Csrz+ksiiuU!0JM165K3hNdvJu)Hp4E zL3=Y4OAvlCmXsxB3Q8)sR!1w>2VBF5XWu(gh^9UbY@>nCdA5TxWGt1JA>Ux-tvECL zSbg&49@gt<-^Yd&Kc~xYgeHPP`3|Xc^d4uTKw2O**a9ICp(q+`Xj4{EXh1z@$3Y0a X{- 10 13 <-> 11 14 <-> 12 -17 <-> 18 -18 <-> 19 -21 <-> 22 -25 <-> 35 -26 <-> 36 +17 <-> 14 +18 <-> 15 +21 <-> 18 +25 <-> 23 +26 <-> 24 +29 <-> 27 +31 <-> 28 +32 <-> 29 +35 <-> 32 +37 <-> 33 +39 <-> 34 +40 <-> 35 +42 <-> 38 +46 <-> 42 +47 <-> 43 +49 <-> 45 +50 <-> 46 +53 <-> 49 +58 <-> 54 +60 <-> 55 +61 <-> 56 +64 <-> 58 +65 <-> 59 +68 <-> 62 From f6ca9605000533a0445e2132c9a0bb6feff10108 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 23 Nov 2021 11:56:04 -0500 Subject: [PATCH 42/85] Optimize try with resources processing --- .../modules/decompiler/TryHelper.java | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java index 42d22343de..05b1e4be2a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java @@ -18,13 +18,7 @@ public static boolean enhanceTryStats(RootStatement root, StructClass cl) { boolean ret = makeTryWithResourceRec(cl, root); if (ret) { - if (cl.getVersion().hasNewTryWithResources()) { - SequenceHelper.condenseSequences(root); - - if (mergeTrys(root)) { - SequenceHelper.condenseSequences(root); - } - } else { + if (!cl.getVersion().hasNewTryWithResources()) { SequenceHelper.condenseSequences(root); if (collapseTryRec(root)) { @@ -33,32 +27,49 @@ public static boolean enhanceTryStats(RootStatement root, StructClass cl) { } } + if (cl.getVersion().hasNewTryWithResources()) { + SequenceHelper.condenseSequences(root); + + if (mergeTrys(root)) { + SequenceHelper.condenseSequences(root); + } + } + return ret; } private static boolean makeTryWithResourceRec(StructClass cl, Statement stat) { // TODO: new try with resources *reruns the entire processing loop after a single one is run.* That is not efficient and could be optimized if (cl.getVersion().hasNewTryWithResources()) { + boolean ret = false; if (stat.type == Statement.TYPE_TRYCATCH) { if (TryWithResourcesProcessor.makeTryWithResourceJ11((CatchStatement) stat)) { - return true; + ret = true; } } + + for (Statement st : new ArrayList<>(stat.getStats())) { + if (makeTryWithResourceRec(cl, st)) { + ret = true; + } + } + + return ret; } else { if (stat.type == Statement.TYPE_CATCHALL && ((CatchAllStatement) stat).isFinally()) { if (TryWithResourcesProcessor.makeTryWithResource((CatchAllStatement) stat)) { return true; } } - } - for (Statement st : new ArrayList<>(stat.getStats())) { - if (makeTryWithResourceRec(cl, st)) { - return true; + for (Statement st : new ArrayList<>(stat.getStats())) { + if (makeTryWithResourceRec(cl, st)) { + return true; + } } - } - return false; + return false; + } } // J11+ From 639b75e880f2b0dce8c9be3aa03f2bbaf25a56e6 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 23 Nov 2021 14:24:00 -0500 Subject: [PATCH 43/85] Optimize pattern match processing --- .../decompiler/main/rels/DecompileRecord.java | 2 +- .../modules/decompiler/PatternMatchProcessor.java | 15 +++++++++++---- .../decompiler/stats/GeneralStatement.java | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/rels/DecompileRecord.java b/src/org/jetbrains/java/decompiler/main/rels/DecompileRecord.java index 61abc68786..a7d5d49d4d 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/DecompileRecord.java +++ b/src/org/jetbrains/java/decompiler/main/rels/DecompileRecord.java @@ -60,7 +60,7 @@ public List getNames() { public void print() { for (int i = 0; i < this.names.size(); i++) { - System.out.println(i + " " + this.names.get(0)); + System.out.println(i + " " + this.names.get(i)); } } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/PatternMatchProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/PatternMatchProcessor.java index ff67756c37..72f10e1b17 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/PatternMatchProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/PatternMatchProcessor.java @@ -19,21 +19,28 @@ */ public final class PatternMatchProcessor { public static boolean matchInstanceof(RootStatement root) { - return matchInstanceofRec(root, root); + boolean res = matchInstanceofRec(root, root); + + if (res) { + SequenceHelper.condenseSequences(root); + } + + return res; } private static boolean matchInstanceofRec(Statement statement, RootStatement root) { + boolean res = false; for (Statement stat : statement.getStats()) { if (matchInstanceofRec(stat, root)) { - return true; + res = true; } } if (statement instanceof IfStatement) { - return handleIf((IfStatement) statement, root); + res |= handleIf((IfStatement) statement, root); } - return false; + return res; } private static boolean handleIf(IfStatement statement, RootStatement root) { 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 27a1d73dce..110a2fb45b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java @@ -52,6 +52,7 @@ public TextBuffer toJava(int indent) { buf.append(stat.toJava(indent + 1)); } buf.appendIndent(indent).append("}"); + buf.appendLineSeparator(); return buf; } From b2de8793e190d10476b6cf862a2b5f5cf3744f83 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 23 Nov 2021 16:10:03 -0500 Subject: [PATCH 44/85] Move try with resources processing to before label identification --- .../main/rels/MethodProcessorRunnable.java | 6 +++--- .../decompiler/TryWithResourcesProcessor.java | 7 ++----- .../jetbrains/java/decompiler/util/DotExporter.java | 12 +++++++++++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java index d70259cdeb..f02f3d35a7 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java +++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java @@ -259,14 +259,14 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe } } - LabelHelper.identifyLabels(root); - decompileRecord.add("IdentifyLabels", root); - if (TryHelper.enhanceTryStats(root, cl)) { decompileRecord.add("EnhanceTry", root); continue; } + LabelHelper.identifyLabels(root); + decompileRecord.add("IdentifyLabels", root); + if (InlineSingleBlockHelper.inlineSingleBlocks(root)) { decompileRecord.add("InlineSingleBlocks", root); continue; diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java index 3e5c678096..f705696b59 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java @@ -4,6 +4,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.modules.decompiler.stats.*; import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.util.DotExporter; import java.util.ArrayList; import java.util.Iterator; @@ -409,12 +410,8 @@ private static boolean removeRedundantThrow(BasicBlockStatement initBlock, Catch catchStat.getVars().remove(i - 1); catchStat.getStats().remove(i); - for (StatEdge edge : temp.getAllPredecessorEdges()) { - edge.getSource().removeSuccessor(edge); - } - for (StatEdge edge : temp.getAllSuccessorEdges()) { - edge.getDestination().removePredecessor(edge); + edge.getSource().removeSuccessor(edge); } removed = true; diff --git a/src/org/jetbrains/java/decompiler/util/DotExporter.java b/src/org/jetbrains/java/decompiler/util/DotExporter.java index 01715b163a..2ced487722 100644 --- a/src/org/jetbrains/java/decompiler/util/DotExporter.java +++ b/src/org/jetbrains/java/decompiler/util/DotExporter.java @@ -110,7 +110,17 @@ private static String statToDot(Statement stat, String name) { for (StatEdge labelEdge : st.getLabelEdges()) { String src = labelEdge.getSource().id + (labelEdge.getSource().getSuccessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty()?"":"000000");; String destId = labelEdge.getDestination().id + (labelEdge.getDestination().getSuccessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty()?"":"000000"); - buffer.append(src + "->" + destId + " [color=orange,label=\"Label Edge (Contained by " + st.id + ")\"];\r\n"); + String data = ""; + if (labelEdge.labeled) { + data += "Labeled"; + } + if (labelEdge.labeled && labelEdge.explicit) { + data += ", "; + } + if (labelEdge.explicit) { + data += "Explicit"; + } + buffer.append(src + "->" + destId + " [color=orange,label=\"Label Edge (" + data + ") (Contained by " + st.id + ")\"];\r\n"); } for (Statement neighbour : st.getNeighbours(Statement.STATEDGE_ALL, Statement.DIRECTION_FORWARD)) { From 79ed291b531fd1456dff6e69225c4e9a947be045 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Thu, 25 Nov 2021 12:14:55 -0500 Subject: [PATCH 45/85] Rewrite try with resources, improve cases where there are breaks out of body --- .../modules/decompiler/TryHelper.java | 3 +- .../decompiler/TryWithResourcesProcessor.java | 242 +++--- .../decompiler/stats/BasicBlockStatement.java | 7 + .../modules/decompiler/stats/Statement.java | 4 + .../java/decompiler/SingleClassesTest.java | 1 - .../pkg/TestTryWithResourcesLoopJ16.dec | 719 +++++------------- .../pkg/TestTryWithResourcesNestedLoop.dec | 422 ++++------ .../pkg/TestTryWithResourcesReturnJ16.dec | 650 +++++----------- .../pkg/TestTryWithResourcesSwitchJ16.dec | 458 +++++------ .../pkg/TestTryWithResourcesSwitchJ16.java | 4 + 10 files changed, 853 insertions(+), 1657 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java index 05b1e4be2a..c173da6b29 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java @@ -32,6 +32,8 @@ public static boolean enhanceTryStats(RootStatement root, StructClass cl) { if (mergeTrys(root)) { SequenceHelper.condenseSequences(root); + + ret = true; } } @@ -39,7 +41,6 @@ public static boolean enhanceTryStats(RootStatement root, StructClass cl) { } private static boolean makeTryWithResourceRec(StructClass cl, Statement stat) { - // TODO: new try with resources *reruns the entire processing loop after a single one is run.* That is not efficient and could be optimized if (cl.getVersion().hasNewTryWithResources()) { boolean ret = false; if (stat.type == Statement.TYPE_TRYCATCH) { diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java index f705696b59..878bb73597 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java @@ -4,11 +4,9 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.modules.decompiler.stats.*; import org.jetbrains.java.decompiler.struct.gen.VarType; -import org.jetbrains.java.decompiler.util.DotExporter; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * Processes try catch statements to turns them into try-with-resources statements wherever possible. @@ -179,159 +177,143 @@ public static boolean makeTryWithResourceJ11(CatchStatement tryStatement) { return false; } - // Prevent processing if we find any weird edges, such as those in PackResourcesAdapterV4 - // TODO: find the root cause of the problem and fix it - List regedges = tryStatement.getSuccessorEdges(StatEdge.TYPE_REGULAR); - if (!regedges.isEmpty()) { - Statement destination = regedges.get(0).getDestination(); - if (destination.type == Statement.TYPE_IF) { - List breaks = destination.getSuccessorEdges(StatEdge.TYPE_BREAK); + Set destinations = findExitpoints(tryStatement); - if (!breaks.isEmpty()) { - - if (!tryStatement.getParent().containsStatement(breaks.get(0).closure)) { - return false; - } - } - } + Statement check = tryStatement; + List preds = new ArrayList<>(); + while (check != null && preds.isEmpty()) { + preds = check.getPredecessorEdges(StatEdge.TYPE_REGULAR); + check = check.getParent(); } - // Find basic block that contains the resource assignment - for (StatEdge edge : tryStatement.getPredecessorEdges(StatEdge.TYPE_REGULAR)) { - // Find predecessors that lead towards the target try statement - if (edge.getDestination().equals(tryStatement) && edge.getSource().type == Statement.TYPE_BASICBLOCK) { - AssignmentExprent assignment = findResourceDef(closeable, edge.getSource()); - - // Remove the resource assignment from the basic block and further process - if (assignment != null) { - edge.getSource().getExprents().remove(assignment); - - // Set the try statement type - tryStatement.setTryType(CatchStatement.RESOURCES); - - // Add resource assignment to try - tryStatement.getResources().add(0, assignment); - - // Destroy catch block - tryStatement.getStats().remove(1); - - // Remove outer close() - Statement parent = tryStatement.getParent(); - - boolean processedClose = false; - for (int i = 0; i < parent.getStats().size(); i++) { - Statement stat = parent.getStats().get(i); - - // Exclude our statement from processing - if (stat == tryStatement) { - continue; - } - - if (nullable) { - // Check for if statement that contains a null check and a close() - if (stat.type == Statement.TYPE_IF) { - IfStatement ifStat = (IfStatement) stat; - Exprent condition = ifStat.getHeadexprent().getCondition(); + if (preds.isEmpty()) { + return false; + } - if (condition.type == Exprent.EXPRENT_FUNCTION) { - // This can sometimes be double inverted negative conditions too, handle that case - FunctionExprent func = unwrapNegations((FunctionExprent) condition); + StatEdge edge = preds.get(0); + if (edge.getSource().type == Statement.TYPE_BASICBLOCK) { + AssignmentExprent assignment = findResourceDef(closeable, edge.getSource()); - // Ensure the exprent is the one we want to remove - if (func.getFuncType() == FunctionExprent.FUNCTION_NE && func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR && func.getLstOperands().get(1).getExprType().equals(VarType.VARTYPE_NULL)) { - if (func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR && ((VarExprent)func.getLstOperands().get(0)).getVarVersionPair().equals(closeable.getVarVersionPair())) { - // TODO: add APIs to do this automatically + if (assignment == null) { + return false; + } - // First start by removing the contents of the if statement. - // This block's connections need to be removed first before we can move onto the statement itself. + for (Statement destination : destinations) { + if (!isValid(destination, closeable, nullable)) { + return false; + } + } - // Contents of the if statement - Statement ifBlock = ifStat.getIfstat(); + for (Statement destination : destinations) { + removeClose(destination, nullable); + } - // Disconnect edges to and from the inside of block's contents - for (StatEdge suc : ifBlock.getAllSuccessorEdges()) { - ifBlock.removeSuccessor(suc); - } + edge.getSource().getExprents().remove(assignment); - // Disconnect predecessors - for (StatEdge pred : ifBlock.getAllPredecessorEdges()) { - // Disconnect successors from pred to the block - pred.getSource().removeSuccessor(pred); - ifBlock.removePredecessor(pred); - } + // Set the try statement type + tryStatement.setTryType(CatchStatement.RESOURCES); - // Remove inner block from the statement - ifStat.getStats().removeWithKey(ifBlock.id); + // Add resource assignment to try + tryStatement.getResources().add(0, assignment); - // Start processing the actual if statement + // Destroy catch block + tryStatement.getStats().remove(1); - // Get successor, which will be connected to predecessors in place of the if statement - StatEdge successor = ifStat.getAllSuccessorEdges().get(0); + return true; + } - for (StatEdge pred : ifStat.getAllPredecessorEdges()) { - Statement predStat = pred.getSource(); - // Disconnect if stat's predecessor from the stat - predStat.removeSuccessor(pred); + return false; + } - // Connect predecessor of if stat to it's successor, circumventing it + private static boolean isValid(Statement stat, VarExprent closeable, boolean nullable) { + if (nullable) { + // Check for if statement that contains a null check and a close() + if (stat.type == Statement.TYPE_IF) { + IfStatement ifStat = (IfStatement) stat; + Exprent condition = ifStat.getHeadexprent().getCondition(); + + if (condition.type == Exprent.EXPRENT_FUNCTION) { + // This can sometimes be double inverted negative conditions too, handle that case + FunctionExprent func = unwrapNegations((FunctionExprent) condition); + + // Ensure the exprent is the one we want to remove + if (func.getFuncType() == FunctionExprent.FUNCTION_NE && func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR && func.getLstOperands().get(1).getExprType().equals(VarType.VARTYPE_NULL)) { + if (func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR && ((VarExprent) func.getLstOperands().get(0)).getVarVersionPair().equals(closeable.getVarVersionPair())) { + return true; + } + } + } + } + } else { + if (stat.type == Statement.TYPE_BASICBLOCK) { + if (stat.getExprents() != null && !stat.getExprents().isEmpty()) { + Exprent exprent = stat.getExprents().get(0); - // When the predecessor is the try statement, we add normal control flow, as the successor is located next to the try statement. When it is not, it must be inside the try, so we break out of it. - // This prevents successor blocks from being inlined, as there are still multiple breaks to the successor and not a singular one that can be inlined [TestTryWithResourcesCatchJ16#test1] - // TODO: break closure? - StatEdge newEdge = new StatEdge(predStat == tryStatement ? StatEdge.TYPE_REGULAR : StatEdge.TYPE_BREAK, predStat, successor.getDestination()); - predStat.addSuccessor(newEdge); - } + if (exprent.type == Exprent.EXPRENT_INVOCATION) { + Exprent inst = ((InvocationExprent) exprent).getInstance(); - // Remove successor from if stat, as we've made the control go from it's predecessors to it's successor - ifStat.removeSuccessor(successor); - successor.getDestination().removePredecessor(successor); // TODO: is this needed? + // Ensure the var exprent we want to remove is the right one + if (inst.type == Exprent.EXPRENT_VAR && inst.equals(closeable) && isCloseable(exprent)) { + return true; + } + } + } + } + } - // Remove if statement containing close() check- finally we're done! - parent.getStats().removeWithKey(ifStat.id); + return false; + } - processedClose = true; - } - } - } - } - } else { - if (stat.getExprents() != null) { - Iterator itr = stat.getExprents().iterator(); + private static void removeClose(Statement statement, boolean nullable) { + if (nullable) { + // Breaking out of parent, remove label + // TODO: The underlying problem is that empty labeled basic blocks remove their label but the edge is marked as labeled and explicit. + // label1: { + // ... + // break label1; // identifyLabels() removes this entirely but keeps the edge labeled + // } + // + List edges = statement.getAllSuccessorEdges(); + if (!edges.isEmpty() && edges.get(0).closure == statement.getParent()) { + SequenceHelper.destroyAndFlattenStatement(statement); + } else { + for (StatEdge edge : statement.getFirst().getAllSuccessorEdges()) { + edge.getDestination().removePredecessor(edge); + } - while (itr.hasNext()) { - Exprent exprent = itr.next(); + for (StatEdge edge : ((IfStatement)statement).getIfstat().getAllSuccessorEdges()) { + edge.getDestination().removePredecessor(edge); - // Check and remove the close exprent - if (exprent.type == Exprent.EXPRENT_INVOCATION) { - Exprent inst = ((InvocationExprent) exprent).getInstance(); + if (edge.closure != null) { + edge.closure.getLabelEdges().remove(edge); + } + } - // Ensure the var exprent we want to remove is the right one - if (inst.type == Exprent.EXPRENT_VAR && ((VarExprent)inst).getVarVersionPair().equals(closeable.getVarVersionPair()) && isCloseable(exprent)) { - itr.remove(); // Remove tested exprent + // Keep the label as it's not the parent + statement.destroy(); + } + } else { + statement.getExprents().remove(0); + } + } - processedClose = true; - } - } - } - } - } + private static Set findExitpoints(Statement stat) { + Set edges = new LinkedHashSet<>(); + findEdgesLeaving(stat.getFirst(), stat, edges); - // Processed close, break out of loop to prevent multiple close() exprents from being removed - if (processedClose) { - break; - } - } + return edges.stream().map(StatEdge::getDestination).collect(Collectors.toSet()); + } - if (processedClose) { - return true; - } else { - // TODO: not processing the close() but also transforming the try block is invalid- leave a source level comment here - } - } + private static void findEdgesLeaving(Statement curr, Statement check, Set edges) { + for (StatEdge edge : curr.getAllSuccessorEdges()) { + if (!check.containsStatement(edge.getDestination()) && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) { + edges.add(edge); } } - return false; + for (Statement stat : curr.getStats()) { + findEdgesLeaving(stat, check, edges); + } } private static FunctionExprent unwrapNegations(FunctionExprent func) { 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 69b07406f1..2b49179684 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java @@ -108,6 +108,13 @@ public List getImplicitlyDefinedVars() { return null; } + public static BasicBlockStatement create() { + BasicBlockStatement stat = new BasicBlockStatement(new BasicBlock(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER))); + stat.setExprents(new ArrayList<>()); + + return stat; + } + // ***************************************************************************** // getter and setter methods // ***************************************************************************** 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 79f4d20776..dbc7faa4ae 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java @@ -511,6 +511,10 @@ public void initSimpleCopy() { } } + public final void destroy() { + this.parent.replaceStatement(this, BasicBlockStatement.create()); + } + public void replaceStatement(Statement oldstat, Statement newstat) { if (!stats.containsKey(oldstat.id)) { throw new IllegalStateException("[" + this + "] Cannot replace " + oldstat + " with " + newstat + " because it wasn't found in " + stats); diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index dabb402da5..38e5a6facf 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -485,7 +485,6 @@ private void registerJavaRuntime() { register(JAVA_16, "TestTryWithResourcesLoopJ16"); register(JAVA_16, "TestTryWithResourcesFake"); register(JAVA_16, "TestTryWithResourcesSwitchJ16"); - // TODO: removing the weird edge processing fix in TryWithResourcesProcessor#makeTryWithResourceJ11 produces two returns in a row register(JAVA_16, "TestTryWithResourcesNestedLoop"); } diff --git a/testData/results/pkg/TestTryWithResourcesLoopJ16.dec b/testData/results/pkg/TestTryWithResourcesLoopJ16.dec index 12db1ef9b1..baa8c86809 100644 --- a/testData/results/pkg/TestTryWithResourcesLoopJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesLoopJ16.dec @@ -7,35 +7,11 @@ import java.util.Scanner; public class TestTryWithResourcesLoopJ16 { public void test(File f) throws FileNotFoundException { while(true) { - Scanner s = this.create(f); - - label41: { - try { - if (!s.hasNext()) {// 11 - break label41; - } - + try (Scanner s = this.create(f)) {// 10 + if (s.hasNext()) {// 11 s.next();// 15 - } catch (Throwable var6) {// 10 - if (s != null) { - try { - s.close(); - } catch (Throwable var5) { - var6.addSuppressed(var5); - } - } - - throw var6; + continue; } - - if (s != null) {// 16 - s.close(); - } - continue; - } - - if (s != null) { - s.close(); } return;// 18 @@ -44,95 +20,28 @@ public class TestTryWithResourcesLoopJ16 { public void test1(File f) throws FileNotFoundException { while(f.exists()) {// 21 - Scanner s = this.create(f); - - label40: { - try { - if (s.hasNext()) {// 23 - s.next();// 27 - break label40; - } - } catch (Throwable var6) {// 22 - if (s != null) { - try { - s.close(); - } catch (Throwable var5) { - var6.addSuppressed(var5); - } - } - - throw var6; - } - - if (s != null) { - s.close(); + try (Scanner s = this.create(f)) {// 22 + if (s.hasNext()) {// 23 + s.next();// 27 + continue; } break; } - - if (s != null) {// 28 - s.close(); - } } }// 30 public void test2(File f) throws FileNotFoundException { while(f.exists()) {// 33 - Scanner s = this.create(f); - - label67: { - try { - Scanner s2 = this.create(f);// 35 - - label74: { - try { - if (!s.hasNext()) {// 36 - break label74; - } - - s.next();// 40 - } catch (Throwable var8) { - if (s2 != null) { - try { - s2.close(); - } catch (Throwable var7) { - var8.addSuppressed(var7); - } - } - - throw var8; - } - - if (s2 != null) { - s2.close(); - } - break label67; - } - - if (s2 != null) { - s2.close(); - } - } catch (Throwable var9) {// 34 - if (s != null) { - try { - s.close(); - } catch (Throwable var6) { - var9.addSuppressed(var6); - } - } - - throw var9; - } - - if (s != null) { - s.close(); + try ( + Scanner s = this.create(f);// 34 + Scanner s2 = this.create(f);// 35 + ) { + if (!s.hasNext()) {// 36 + break; } - break; - } - if (s != null) {// 41 - s.close(); + s.next();// 40 } } @@ -140,79 +49,18 @@ public class TestTryWithResourcesLoopJ16 { public void test3(File f) throws FileNotFoundException { while(f.exists()) {// 46 - Scanner s = this.create(f); - - label91: { - label84: { - try { - Scanner s2; - label93: { - s2 = this.create(f);// 48 - - label94: { - try { - if (!s.hasNext()) {// 49 - break label93; - } - - if (s2.hasNext()) {// 51 - break label94; - } - - s.next();// 55 - } catch (Throwable var8) { - if (s2 != null) { - try { - s2.close(); - } catch (Throwable var7) { - var8.addSuppressed(var7); - } - } - - throw var8; - } - - if (s2 != null) { - s2.close(); - } - break label84; - } - - if (s2 != null) { - s2.close(); - } - break label91; - } - - if (s2 != null) { - s2.close(); - } - } catch (Throwable var9) {// 47 - if (s != null) { - try { - s.close(); - } catch (Throwable var6) { - var9.addSuppressed(var6); - } - } - - throw var9; - } - - if (s != null) { - s.close(); - } + try ( + Scanner s = this.create(f);// 47 + Scanner s2 = this.create(f);// 48 + ) { + if (!s.hasNext()) {// 49 break; } - if (s != null) {// 56 - s.close(); + if (!s2.hasNext()) {// 51 + s.next();// 55 + continue; } - continue; - } - - if (s != null) { - s.close(); } return;// 52 @@ -222,59 +70,13 @@ public class TestTryWithResourcesLoopJ16 { public void test4(File f) throws FileNotFoundException { while(f.exists()) {// 61 - Scanner s = this.create(f); - - label74: { - try { - Scanner s2 = this.create(f);// 63 - - label76: { - try { - if (s.hasNext()) {// 64 - s.next();// 68 - break label76; - } - } catch (Throwable var8) { - if (s2 != null) { - try { - s2.close(); - } catch (Throwable var7) { - var8.addSuppressed(var7); - } - } - - throw var8; - } - - if (s2 != null) { - s2.close(); - } - break label74; - } - - if (s2 != null) { - s2.close(); - } - } catch (Throwable var9) {// 62 - if (s != null) { - try { - s.close(); - } catch (Throwable var6) { - var9.addSuppressed(var6); - } - } - - throw var9; - } - - if (s != null) {// 69 - s.close(); + try ( + Scanner s = this.create(f);// 62 + Scanner s2 = this.create(f);// 63 + ) { + if (s.hasNext()) {// 64 + s.next();// 68 } - continue; - } - - if (s != null) { - s.close(); } } @@ -293,335 +95,174 @@ class 'pkg/TestTryWithResourcesLoopJ16' { 3 9 4 9 5 9 - 6 13 - 7 13 - 8 13 - 9 13 - a 13 - d 36 - e 36 - 11 37 - 12 37 - 13 37 - 14 37 - 18 17 - 19 17 - 1a 17 - 1b 17 - 1d 30 - 1e 30 - 21 31 - 22 31 - 23 31 - 24 31 - 28 18 - 29 19 - 2a 19 - 2d 21 - 2e 21 - 34 22 - 39 23 - 3d 27 - 41 40 + 6 10 + 7 10 + 8 10 + 9 10 + a 10 + 18 11 + 19 11 + 1a 11 + 1b 11 + 41 16 } method 'test1 (Ljava/io/File;)V' { - 0 45 - 1 45 - 2 45 - 3 45 - 7 46 - 8 46 - 9 46 - a 46 - b 46 - c 46 - d 50 - e 50 - f 50 - 10 50 - 11 50 - 14 66 - 15 66 - 18 67 - 19 67 - 1a 67 - 1b 67 - 1f 51 - 20 51 - 21 51 - 22 51 - 24 72 - 25 72 - 28 73 - 29 73 - 2a 73 - 2b 73 - 2f 54 - 30 55 - 31 55 - 34 57 - 35 57 - 3b 58 - 40 59 - 44 63 - 48 77 + 0 21 + 1 21 + 2 21 + 3 21 + 7 22 + 8 22 + 9 22 + a 22 + b 22 + c 22 + d 23 + e 23 + f 23 + 10 23 + 11 23 + 1f 24 + 20 24 + 21 24 + 22 24 + 48 31 } method 'test2 (Ljava/io/File;)V' { - 0 80 - 1 80 - 2 80 - 3 80 - 7 81 - 8 81 - 9 81 - a 81 - b 81 - c 81 - d 85 - e 85 - f 85 - 10 85 - 11 85 - 12 85 - 13 89 - 14 89 - 15 89 - 16 89 - 17 89 - 1a 112 - 1b 112 - 1e 113 - 1f 113 - 22 127 - 23 127 - 26 128 - 27 128 - 28 128 - 29 128 - 2d 93 - 2e 93 - 2f 93 - 30 93 - 32 106 - 33 106 - 36 107 - 37 107 - 38 107 - 39 107 - 3d 94 - 3f 95 - 40 95 - 43 97 - 44 97 - 4a 98 - 50 99 - 55 103 - 56 133 - 57 133 - 5a 134 - 5b 134 - 5c 134 - 5d 134 - 61 115 - 62 116 - 63 116 - 66 118 - 67 118 - 6d 119 - 72 120 - 76 124 - 7a 138 + 0 34 + 1 34 + 2 34 + 3 34 + 7 36 + 8 36 + 9 36 + a 36 + b 36 + c 36 + d 37 + e 37 + f 37 + 10 37 + 11 37 + 12 37 + 13 39 + 14 39 + 15 39 + 16 39 + 17 39 + 2d 43 + 2e 43 + 2f 43 + 30 43 + 7a 47 } method 'test3 (Ljava/io/File;)V' { - 0 141 - 1 141 - 2 141 - 3 141 - 7 142 - 8 142 - 9 142 - a 142 - b 142 - c 142 - d 149 - e 149 - f 149 - 10 149 - 11 149 - 12 149 - 13 153 - 14 153 - 15 153 - 16 153 - 17 153 - 1a 186 - 1b 186 - 1e 187 - 1f 187 - 22 201 - 23 201 - 26 202 - 27 202 - 28 202 - 29 202 - 2d 157 - 2e 157 - 2f 157 - 30 157 - 31 157 - 34 180 - 35 180 - 38 181 - 39 181 - 3c 213 - 3d 213 - 40 214 - 41 214 - 44 217 - 45 161 - 46 161 - 47 161 - 48 161 - 4a 174 - 4b 174 - 4e 175 - 4f 175 - 50 175 - 51 175 - 55 162 - 57 163 - 58 163 - 5b 165 - 5c 165 - 62 166 - 68 167 - 6d 171 - 6e 207 - 6f 207 - 72 208 - 73 208 - 74 208 - 75 208 - 79 189 - 7a 190 - 7b 190 - 7e 192 - 7f 192 - 85 193 - 8a 194 - 8e 198 - 92 220 + 0 50 + 1 50 + 2 50 + 3 50 + 7 52 + 8 52 + 9 52 + a 52 + b 52 + c 52 + d 53 + e 53 + f 53 + 10 53 + 11 53 + 12 53 + 13 55 + 14 55 + 15 55 + 16 55 + 17 55 + 2d 59 + 2e 59 + 2f 59 + 30 59 + 31 59 + 44 65 + 45 60 + 46 60 + 47 60 + 48 60 + 92 68 } method 'test4 (Ljava/io/File;)V' { - 0 223 - 1 223 - 2 223 - 3 223 - 7 224 - 8 224 - 9 224 - a 224 - b 224 - c 224 - d 228 - e 228 - f 228 - 10 228 - 11 228 - 12 228 - 13 232 - 14 232 - 15 232 - 16 232 - 17 232 - 1a 248 - 1b 248 - 1e 249 - 1f 249 - 22 275 - 23 275 - 26 276 - 27 276 - 28 276 - 29 276 - 2d 233 - 2e 233 - 2f 233 - 30 233 - 32 254 - 33 254 - 36 255 - 37 255 - 38 255 - 39 255 - 3d 236 - 3f 237 - 40 237 - 43 239 - 44 239 - 4a 240 - 50 241 - 55 245 - 56 269 - 57 269 - 5a 270 - 5b 270 - 5c 270 - 5d 270 - 61 257 - 62 258 - 63 258 - 66 260 - 67 260 - 6d 261 - 72 262 - 76 266 - 7a 280 + 0 71 + 1 71 + 2 71 + 3 71 + 7 73 + 8 73 + 9 73 + a 73 + b 73 + c 73 + d 74 + e 74 + f 74 + 10 74 + 11 74 + 12 74 + 13 76 + 14 76 + 15 76 + 16 76 + 17 76 + 2d 77 + 2e 77 + 2f 77 + 30 77 + 7a 82 } method 'create (Ljava/io/File;)Ljava/util/Scanner;' { - 4 283 - 8 283 + 4 85 + 8 85 } } Lines mapping: -10 <-> 19 -11 <-> 14 -15 <-> 18 -16 <-> 31 -18 <-> 41 -21 <-> 46 -22 <-> 55 -23 <-> 51 -27 <-> 52 -28 <-> 73 -30 <-> 78 -33 <-> 81 -34 <-> 116 -35 <-> 86 -36 <-> 90 -40 <-> 94 -41 <-> 134 -43 <-> 139 -46 <-> 142 -47 <-> 190 -48 <-> 150 -49 <-> 154 -51 <-> 158 -52 <-> 218 -55 <-> 162 -56 <-> 208 -58 <-> 221 -61 <-> 224 -62 <-> 258 -63 <-> 229 -64 <-> 233 -68 <-> 234 -69 <-> 270 -71 <-> 281 -74 <-> 284 +10 <-> 10 +11 <-> 11 +15 <-> 12 +18 <-> 17 +21 <-> 22 +22 <-> 23 +23 <-> 24 +27 <-> 25 +30 <-> 32 +33 <-> 35 +34 <-> 37 +35 <-> 38 +36 <-> 40 +40 <-> 44 +43 <-> 48 +46 <-> 51 +47 <-> 53 +48 <-> 54 +49 <-> 56 +51 <-> 60 +52 <-> 66 +55 <-> 61 +58 <-> 69 +61 <-> 72 +62 <-> 74 +63 <-> 75 +64 <-> 77 +68 <-> 78 +71 <-> 83 +74 <-> 86 +Not mapped: +16 +28 +41 +56 +69 diff --git a/testData/results/pkg/TestTryWithResourcesNestedLoop.dec b/testData/results/pkg/TestTryWithResourcesNestedLoop.dec index df42caa2b4..e3ad70436d 100644 --- a/testData/results/pkg/TestTryWithResourcesNestedLoop.dec +++ b/testData/results/pkg/TestTryWithResourcesNestedLoop.dec @@ -8,283 +8,181 @@ import java.nio.file.Path; public class TestTryWithResourcesNestedLoop { public static InputStream test(Path base, Path overlay, int width, int left, int top, int right, int bottom) throws IOException { - InputStream lv = Files.newInputStream(base); - - ByteArrayInputStream var23; - label105: { - try { - InputStream lv2; - label107: { - lv2 = Files.newInputStream(overlay);// 12 - - try { - int n = lv.available();// 14 - int o = lv.read();// 15 - if (n != lv2.available() || o != lv2.read()) {// 17 - break label107; - } - - try (ByteArrayInputStream lv3 = new ByteArrayInputStream(new byte[0], n, o)) {// 18 - int p = n / width;// 19 - - for(int q = top * p; q < bottom * p; ++q) {// 20 - for(int r = left * p; r < right * p; ++r) {// 21 - lv2.read(new byte[0], r, q);// 22 - lv.read(new byte[0], r, q);// 23 - lv3.read(new byte[0], r, q);// 25 - } - } - - var23 = new ByteArrayInputStream(lv3.readAllBytes()); - } - } catch (Throwable var21) { - if (lv2 != null) { - try { - lv2.close(); - } catch (Throwable var18) { - var21.addSuppressed(var18); - } + try ( + InputStream lv = Files.newInputStream(base);// 11 + InputStream lv2 = Files.newInputStream(overlay);// 12 + ) { + int n = lv.available();// 14 + int o = lv.read();// 15 + if (n == lv2.available() && o == lv2.read()) {// 17 + try (ByteArrayInputStream lv3 = new ByteArrayInputStream(new byte[0], n, o)) {// 18 + int p = n / width;// 19 + + for(int q = top * p; q < bottom * p; ++q) {// 20 + for(int r = left * p; r < right * p; ++r) {// 21 + lv2.read(new byte[0], r, q);// 22 + lv.read(new byte[0], r, q);// 23 + lv3.read(new byte[0], r, q);// 25 } - - throw var21; } - if (lv2 != null) { - lv2.close(); - } - break label105; + return new ByteArrayInputStream(lv3.readAllBytes());// 29 } - - if (lv2 != null) { - lv2.close(); - } - } catch (Throwable var22) {// 11 - if (lv != null) { - try { - lv.close(); - } catch (Throwable var17) { - var22.addSuppressed(var17); - } - } - - throw var22; } - - if (lv != null) {// 32 - lv.close(); - } - - return null;// 34 - } - - if (lv != null) { - lv.close(); } - return var23;// 29 + return null;// 34 } } class 'pkg/TestTryWithResourcesNestedLoop' { method 'test (Ljava/nio/file/Path;Ljava/nio/file/Path;IIIII)Ljava/io/InputStream;' { - 0 10 - 5 10 - 6 10 - 7 10 - 8 10 - 9 10 - a 17 - f 17 - 10 17 - 11 17 - 12 17 - 13 17 - 14 20 - 15 20 - 16 20 - 17 20 - 18 20 - 19 20 - 1a 20 - 1b 21 - 1c 21 - 1d 21 - 1e 21 - 1f 21 - 20 21 - 21 21 - 22 22 - 23 22 - 24 22 - 25 22 - 26 22 - 27 22 - 28 22 - 29 22 - 2c 22 - 2d 22 - 2e 22 - 2f 22 - 30 22 - 31 22 - 32 22 - 33 22 - 3a 26 - 3d 26 - 3e 26 - 3f 26 - 40 26 - 44 26 - 45 26 - 46 27 - 47 27 - 48 27 - 49 27 - 4a 27 - 4b 27 - 4c 29 - 4d 29 - 4e 29 - 4f 29 - 50 29 - 51 29 - 52 29 - 53 29 - 54 29 - 55 29 - 56 29 - 57 29 - 58 29 - 59 29 - 5a 29 - 5d 30 - 5e 30 - 5f 30 - 60 30 - 61 30 - 62 30 - 63 30 - 64 30 - 65 30 - 66 30 - 67 30 - 68 30 - 69 30 - 6a 30 - 6d 31 - 6e 31 - 6f 31 - 72 31 - 73 31 - 74 31 - 75 31 - 76 31 - 77 31 - 78 31 - 7b 32 - 7c 32 - 7d 32 - 80 32 - 81 32 - 82 32 - 83 32 - 84 32 - 85 32 - 86 32 - 89 33 - 8a 33 - 8b 33 - 8e 33 - 8f 33 - 90 33 - 91 33 - 92 33 - 93 33 - 94 33 - 96 30 - 97 30 - 98 30 - 9c 29 - 9d 29 - 9e 29 - a6 37 - a7 37 - a8 37 - a9 37 - aa 37 - ae 37 - af 37 - b5 51 - b6 51 - b7 51 - ba 52 - bb 52 - bc 52 - bf 79 - c0 79 - c1 79 - c4 80 - c5 80 - c6 80 - c9 83 - ca 83 - cb 83 - e2 57 - e3 57 - e4 57 - e7 58 - e8 58 - e9 58 - ea 58 - eb 58 - ef 39 - f1 40 - f2 40 - f3 40 - f6 42 - f7 42 - f8 42 - fe 43 - 104 44 - 109 48 - 10a 72 - 10b 72 - 10c 72 - 10f 73 - 110 73 - 111 73 - 112 73 - 113 73 - 117 60 - 119 61 - 11a 61 - 11b 61 - 11e 63 - 11f 63 - 120 63 - 126 64 - 12c 65 - 131 69 - 132 76 - 133 76 + 0 11 + 5 11 + 6 11 + 7 11 + 8 11 + 9 11 + a 12 + f 12 + 10 12 + 11 12 + 12 12 + 13 12 + 14 14 + 15 14 + 16 14 + 17 14 + 18 14 + 19 14 + 1a 14 + 1b 15 + 1c 15 + 1d 15 + 1e 15 + 1f 15 + 20 15 + 21 15 + 22 16 + 23 16 + 24 16 + 25 16 + 26 16 + 27 16 + 28 16 + 29 16 + 2c 16 + 2d 16 + 2e 16 + 2f 16 + 30 16 + 31 16 + 32 16 + 33 16 + 3a 17 + 3d 17 + 3e 17 + 3f 17 + 40 17 + 44 17 + 45 17 + 46 18 + 47 18 + 48 18 + 49 18 + 4a 18 + 4b 18 + 4c 20 + 4d 20 + 4e 20 + 4f 20 + 50 20 + 51 20 + 52 20 + 53 20 + 54 20 + 55 20 + 56 20 + 57 20 + 58 20 + 59 20 + 5a 20 + 5d 21 + 5e 21 + 5f 21 + 60 21 + 61 21 + 62 21 + 63 21 + 64 21 + 65 21 + 66 21 + 67 21 + 68 21 + 69 21 + 6a 21 + 6d 22 + 6e 22 + 6f 22 + 72 22 + 73 22 + 74 22 + 75 22 + 76 22 + 77 22 + 78 22 + 7b 23 + 7c 23 + 7d 23 + 80 23 + 81 23 + 82 23 + 83 23 + 84 23 + 85 23 + 86 23 + 89 24 + 8a 24 + 8b 24 + 8e 24 + 8f 24 + 90 24 + 91 24 + 92 24 + 93 24 + 94 24 + 96 21 + 97 21 + 98 21 + 9c 20 + 9d 20 + 9e 20 + a6 28 + a7 28 + a8 28 + a9 28 + aa 28 + cb 28 + 132 33 + 133 33 } } Lines mapping: -11 <-> 61 -12 <-> 18 -14 <-> 21 -15 <-> 22 -17 <-> 23 -18 <-> 27 -19 <-> 28 -20 <-> 30 -21 <-> 31 -22 <-> 32 -23 <-> 33 -25 <-> 34 -29 <-> 84 -32 <-> 73 -34 <-> 77 +11 <-> 12 +12 <-> 13 +14 <-> 15 +15 <-> 16 +17 <-> 17 +18 <-> 18 +19 <-> 19 +20 <-> 21 +21 <-> 22 +22 <-> 23 +23 <-> 24 +25 <-> 25 +29 <-> 29 +34 <-> 34 Not mapped: 30 +32 diff --git a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec index 238392661a..ccbb1feeb7 100644 --- a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec @@ -91,177 +91,55 @@ public class TestTryWithResourcesReturnJ16 { } public String testComplex(File f, File f2, File f3) throws FileNotFoundException { - Scanner scanner = this.create(f); - - String o; - label104: { - Object var16; - try { - Scanner s2 = this.create(f2);// 43 - - label106: { - try { - scanner.next();// 44 - if (!scanner.hasNext() || !s2.hasNext()) {// 46 - var16 = null; - break label106; - } - - try (Scanner s = this.create(f3)) {// 50 - scanner.next();// 51 - - for(int i = 0; i < s.nextInt(); ++i) {// 53 - System.out.println(i);// 54 - } - - o = s.next();// 57 - } - } catch (Throwable var14) { - if (s2 != null) { - try { - s2.close(); - } catch (Throwable var11) { - var14.addSuppressed(var11); - } - } - - throw var14; + Object var16; + try ( + Scanner scanner = this.create(f);// 42 + Scanner s2 = this.create(f2);// 43 + ) { + scanner.next();// 44 + if (scanner.hasNext() && s2.hasNext()) {// 46 + try (Scanner s = this.create(f3)) {// 50 + scanner.next();// 51 + + for(int i = 0; i < s.nextInt(); ++i) {// 53 + System.out.println(i);// 54 } - if (s2 != null) { - s2.close(); - } - break label104; - } - - if (s2 != null) { - s2.close(); - } - } catch (Throwable var15) {// 42 - if (scanner != null) { - try { - scanner.close(); - } catch (Throwable var10) { - var15.addSuppressed(var10); - } + return s.next();// 57 61 } - - throw var15; - } - - if (scanner != null) { - scanner.close(); } - return (String)var16;// 47 + var16 = null; } - if (scanner != null) {// 59 - scanner.close(); - } - - return o;// 61 + return (String)var16;// 47 } public String testComplex1(File f, File f2, File f3) throws FileNotFoundException { - Scanner scanner = this.create(f); - - String var6; - label74: { - try { - Scanner s2 = this.create(f2);// 66 - - label76: { - try { - if (!scanner.hasNext() || !s2.hasNext()) {// 67 - s2.next();// 71 - break label76; - } - - var6 = scanner.next(); - } catch (Throwable var10) { - if (s2 != null) { - try { - s2.close(); - } catch (Throwable var9) { - var10.addSuppressed(var9); - } - } - - throw var10; - } - - if (s2 != null) { - s2.close(); - } - break label74; - } - - if (s2 != null) { - s2.close(); - } - } catch (Throwable var11) {// 65 - if (scanner != null) { - try { - scanner.close(); - } catch (Throwable var8) { - var11.addSuppressed(var8); - } - } - - throw var11; - } - - if (scanner != null) {// 72 - scanner.close(); + try ( + Scanner scanner = this.create(f);// 65 + Scanner s2 = this.create(f2);// 66 + ) { + if (scanner.hasNext() && s2.hasNext()) {// 67 + return scanner.next();// 68 } - return null;// 74 - } - - if (scanner != null) { - scanner.close(); + s2.next();// 71 } - return var6;// 68 + return null;// 74 } public String testComplex2(File f, File f2, File f3) throws FileNotFoundException { - Scanner scanner = this.create(f); - - String var5; - label43: { - try { - if (scanner.hasNext()) {// 79 - var5 = scanner.next(); - break label43; - } - - scanner.next();// 83 - } catch (Throwable var8) {// 78 - if (scanner != null) { - try { - scanner.close(); - } catch (Throwable var7) { - var8.addSuppressed(var7); - } - } - - throw var8; - } - - if (scanner != null) {// 84 - scanner.close(); + try (Scanner scanner = this.create(f)) {// 78 + if (scanner.hasNext()) {// 79 + return scanner.next();// 80 } - return null;// 86 - } - - if (scanner != null) { - scanner.close(); + scanner.next();// 83 } - return var5;// 80 + return null;// 86 } private Scanner create(File file) throws FileNotFoundException { @@ -300,291 +178,159 @@ class 'pkg/TestTryWithResourcesReturnJ16' { } method 'testComplex (Ljava/io/File;Ljava/io/File;Ljava/io/File;)Ljava/lang/String;' { - 0 93 - 1 93 - 2 93 - 3 93 - 4 93 - 5 93 - 6 93 - 7 99 - 8 99 - 9 99 - a 99 - b 99 - c 99 - d 99 - e 103 - f 103 - 10 103 - 11 103 - 12 103 - 14 104 - 15 104 - 16 104 - 17 104 - 18 104 - 19 104 - 1c 104 - 1d 104 - 1e 104 - 1f 104 - 20 104 - 21 104 - 24 105 - 25 105 - 26 105 - 27 136 - 28 136 - 29 136 - 2c 137 - 2d 137 - 2e 137 - 31 151 - 32 151 - 33 151 - 36 152 - 37 152 - 38 152 - 3b 155 - 3c 155 - 3d 155 - 3e 109 - 3f 109 - 40 109 - 41 109 - 42 109 - 43 109 - 44 109 - 45 110 - 46 110 - 47 110 - 48 110 - 49 110 - 4b 112 - 4c 112 - 4d 112 - 4e 112 - 4f 112 - 50 112 - 51 112 - 52 112 - 53 112 - 54 112 - 55 112 - 58 113 - 59 113 - 5a 113 - 5b 113 - 5c 113 - 5d 113 - 5e 113 - 5f 113 - 60 112 - 61 112 - 62 112 - 66 116 - 67 116 - 68 116 - 69 116 - 6a 116 - 6b 116 - 6c 116 - 95 130 - 96 130 - 97 130 - 9a 131 - 9b 131 - 9c 131 - 9d 131 - 9e 131 - a2 118 - a4 119 - a5 119 - a6 119 - a9 121 - aa 121 - ab 121 - b1 122 - b7 123 - bc 127 - bd 158 - be 158 - bf 158 - c2 159 - c3 159 - c4 159 - c5 159 - c6 159 - ca 139 - cc 140 - cd 140 - ce 140 - d1 142 - d2 142 - d3 142 - d9 143 - df 144 - e4 148 - e5 162 - e6 162 - e7 162 + 0 95 + 1 95 + 2 95 + 3 95 + 4 95 + 5 95 + 6 95 + 7 96 + 8 96 + 9 96 + a 96 + b 96 + c 96 + d 96 + e 98 + f 98 + 10 98 + 11 98 + 12 98 + 14 99 + 15 99 + 16 99 + 17 99 + 18 99 + 19 99 + 1c 99 + 1d 99 + 1e 99 + 1f 99 + 20 99 + 21 99 + 24 111 + 25 111 + 26 111 + 3b 114 + 3c 114 + 3d 114 + 3e 100 + 3f 100 + 40 100 + 41 100 + 42 100 + 43 100 + 44 100 + 45 101 + 46 101 + 47 101 + 48 101 + 49 101 + 4b 103 + 4c 103 + 4d 103 + 4e 103 + 4f 103 + 50 103 + 51 103 + 52 103 + 53 103 + 54 103 + 55 103 + 58 104 + 59 104 + 5a 104 + 5b 104 + 5c 104 + 5d 104 + 5e 104 + 5f 104 + 60 103 + 61 103 + 62 103 + 66 107 + 67 107 + 68 107 + 69 107 + 6a 107 + e7 107 } method 'testComplex1 (Ljava/io/File;Ljava/io/File;Ljava/io/File;)Ljava/lang/String;' { - 0 166 - 1 166 - 2 166 - 3 166 - 4 166 - 5 166 - 6 166 - 7 171 - 8 171 - 9 171 - a 171 - b 171 - c 171 - d 171 - e 175 - f 175 - 10 175 - 11 175 - 12 175 - 13 175 - 16 175 - 17 175 - 18 175 - 19 175 - 1a 175 - 1b 175 - 1e 180 - 1f 180 - 20 180 - 21 180 - 22 180 - 23 180 - 24 180 - 25 193 - 26 193 - 27 193 - 2a 194 - 2b 194 - 2c 194 - 2f 221 - 30 221 - 31 221 - 34 222 - 35 222 - 36 222 - 39 225 - 3a 225 - 3b 225 - 3c 176 - 3d 176 - 3e 176 - 3f 176 - 40 176 - 42 199 - 43 199 - 44 199 - 47 200 - 48 200 - 49 200 - 4a 200 - 4b 200 - 4f 181 - 51 182 - 52 182 - 53 182 - 56 184 - 57 184 - 58 184 - 5e 185 - 64 186 - 69 190 - 6a 214 - 6b 214 - 6c 214 - 6f 215 - 70 215 - 71 215 - 72 215 - 73 215 - 77 202 - 79 203 - 7a 203 - 7b 203 - 7e 205 - 7f 205 - 80 205 - 86 206 - 8c 207 - 91 211 - 92 218 - 93 218 + 0 119 + 1 119 + 2 119 + 3 119 + 4 119 + 5 119 + 6 119 + 7 120 + 8 120 + 9 120 + a 120 + b 120 + c 120 + d 120 + e 122 + f 122 + 10 122 + 11 122 + 12 122 + 13 122 + 16 122 + 17 122 + 18 122 + 19 122 + 1a 122 + 1b 122 + 1e 123 + 1f 123 + 20 123 + 21 123 + 22 123 + 3b 123 + 3c 126 + 3d 126 + 3e 126 + 3f 126 + 40 126 + 92 129 + 93 129 } method 'testComplex2 (Ljava/io/File;Ljava/io/File;Ljava/io/File;)Ljava/lang/String;' { - 0 229 - 1 229 - 2 229 - 3 229 - 4 229 - 5 229 - 6 229 - 7 234 - 8 234 - 9 234 - a 234 - b 234 - c 234 - f 235 - 10 235 - 11 235 - 12 235 - 13 235 - 14 235 - 15 235 - 16 259 - 17 259 - 18 259 - 1b 260 - 1c 260 - 1d 260 - 20 263 - 21 263 - 22 263 - 23 239 - 24 239 - 25 239 - 26 239 - 27 239 - 29 252 - 2a 252 - 2b 252 - 2e 253 - 2f 253 - 30 253 - 31 253 - 32 253 - 36 240 - 38 241 - 39 241 - 3a 241 - 3d 243 - 3e 243 - 3f 243 - 45 244 - 4b 245 - 50 249 - 51 256 - 52 256 + 0 133 + 1 133 + 2 133 + 3 133 + 4 133 + 5 133 + 6 133 + 7 134 + 8 134 + 9 134 + a 134 + b 134 + c 134 + f 135 + 10 135 + 11 135 + 12 135 + 13 135 + 22 135 + 23 138 + 24 138 + 25 138 + 26 138 + 27 138 + 51 141 + 52 141 } method 'create (Ljava/io/File;)Ljava/util/Scanner;' { - 4 267 - 8 267 + 4 145 + 8 145 } } @@ -595,35 +341,35 @@ Lines mapping: 16 <-> 23 21 <-> 28 24 <-> 32 -42 <-> 140 -43 <-> 100 -44 <-> 104 -46 <-> 105 -47 <-> 156 -50 <-> 110 -51 <-> 111 -53 <-> 113 -54 <-> 114 -57 <-> 117 -59 <-> 159 -61 <-> 163 -65 <-> 203 -66 <-> 172 -67 <-> 176 -68 <-> 226 -71 <-> 177 -72 <-> 215 -74 <-> 219 -78 <-> 241 -79 <-> 235 -80 <-> 264 -83 <-> 240 -84 <-> 253 -86 <-> 257 -90 <-> 268 +42 <-> 96 +43 <-> 97 +44 <-> 99 +46 <-> 100 +47 <-> 115 +50 <-> 101 +51 <-> 102 +53 <-> 104 +54 <-> 105 +57 <-> 108 +61 <-> 108 +65 <-> 120 +66 <-> 121 +67 <-> 123 +68 <-> 124 +71 <-> 127 +74 <-> 130 +78 <-> 134 +79 <-> 135 +80 <-> 136 +83 <-> 139 +86 <-> 142 +90 <-> 146 Not mapped: 11 17 22 23 58 +59 +72 +84 diff --git a/testData/results/pkg/TestTryWithResourcesSwitchJ16.dec b/testData/results/pkg/TestTryWithResourcesSwitchJ16.dec index d3d57f067e..91a3f5778c 100644 --- a/testData/results/pkg/TestTryWithResourcesSwitchJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesSwitchJ16.dec @@ -22,115 +22,61 @@ public class TestTryWithResourcesSwitchJ16 { }// 21 public void test1(File f) throws FileNotFoundException { - Scanner s = this.create(f); - - label43: { - label42: { - try { - switch(s.nextInt()) {// 26 - case 1: - System.out.println("1");// 28 - break label42;// 29 - case 2: - System.out.println("2");// 31 - break; - default: - System.out.println("default");// 34 - break label42; - } - } catch (Throwable var6) {// 25 - if (s != null) { - try { - s.close(); - } catch (Throwable var5) { - var6.addSuppressed(var5); - } - } - - throw var6; + try (Scanner s = this.create(f)) {// 25 + label56: { + switch(s.nextInt()) {// 26 + case 1: + System.out.println("1");// 28 + break;// 29 + case 2: + System.out.println("2");// 31 + break label56; + default: + System.out.println("default");// 34 } - if (s != null) { - s.close(); - } - break label43; - } - - if (s != null) {// 36 - s.close(); + System.out.println("after switch");// 37 } } - System.out.println("after");// 38 - if (f.exists()) {// 39 - System.out.println("exists");// 40 + System.out.println("after");// 40 + if (f.exists()) {// 41 + System.out.println("exists");// 42 } - }// 42 + }// 44 public int test2(File f) throws FileNotFoundException { - Scanner s = this.create(f); - - byte var3; - label57: { - label52: { - label51: { - try { - switch(s.nextInt()) {// 47 - case 1: - System.out.println("1");// 49 - break label51;// 50 - case 2: - System.out.println("2");// 52 - break; - case 3: - System.out.println("3");// 55 - var3 = 1; - break label57; - default: - System.out.println("default");// 58 - break label51; - } - } catch (Throwable var6) {// 46 - if (s != null) { - try { - s.close(); - } catch (Throwable var5) { - var6.addSuppressed(var5); - } - } - - throw var6; - } - - if (s != null) { - s.close(); - } - break label52; - } - - if (s != null) {// 60 - s.close(); + try (Scanner s = this.create(f)) {// 48 + label69: { + switch(s.nextInt()) {// 49 + case 1: + System.out.println("1");// 51 + break;// 52 + case 2: + System.out.println("2");// 54 + break label69; + case 3: + System.out.println("3");// 57 + return 1;// 58 + default: + System.out.println("default");// 60 } - } - System.out.println("after");// 62 - if (f.exists()) {// 63 - System.out.println("exists");// 64 + System.out.println("after switch");// 63 } - - return 0;// 67 } - if (s != null) { - s.close(); + System.out.println("after");// 66 + if (f.exists()) {// 67 + System.out.println("exists");// 68 } - return var3;// 56 + return 0;// 71 } private Scanner create(File file) throws FileNotFoundException { - return new Scanner(file);// 71 + return new Scanner(file);// 75 } } @@ -181,169 +127,135 @@ class 'pkg/TestTryWithResourcesSwitchJ16' { 3 24 4 24 5 24 - 6 29 - 7 29 - 8 29 - 9 29 - a 29 - 24 31 - 25 31 - 26 31 - 27 31 - 28 31 - 29 31 - 2a 31 - 2b 31 - 2c 32 - 2f 34 - 30 34 - 31 34 - 32 34 - 33 34 - 34 34 - 37 52 - 38 52 - 3b 53 - 3c 53 - 3d 53 - 3e 53 - 42 37 - 43 37 - 44 37 - 45 37 - 46 37 - 47 37 - 4a 58 - 4b 58 - 4e 59 - 4f 59 - 50 59 - 51 59 - 55 40 - 56 41 - 57 41 - 5a 43 - 5b 43 - 61 44 - 66 45 - 6a 49 - 6b 63 - 6c 63 - 6d 63 - 6e 63 - 6f 63 - 70 63 - 71 63 - 72 63 - 73 64 - 74 64 - 75 64 - 76 64 - 77 64 - 7a 65 - 7b 65 - 7c 65 - 7d 65 - 7e 65 - 7f 65 - 82 68 + 6 26 + 7 26 + 8 26 + 9 26 + a 26 + 24 28 + 25 28 + 26 28 + 27 28 + 28 28 + 29 28 + 2a 28 + 2b 28 + 2c 29 + 2f 31 + 30 31 + 31 31 + 32 31 + 33 31 + 34 31 + 42 34 + 43 34 + 44 34 + 45 34 + 46 34 + 47 34 + 4a 37 + 4b 37 + 4c 37 + 4d 37 + 4e 37 + 4f 37 + 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 + 82 43 + 83 43 + 84 43 + 85 43 + 86 43 + 87 43 + 8a 46 } method 'test2 (Ljava/io/File;)I' { - 0 71 - 1 71 - 2 71 - 3 71 - 4 71 - 5 71 - 6 78 - 7 78 - 8 78 - 9 78 - a 78 - 24 80 - 25 80 - 26 80 - 27 80 - 28 80 - 29 80 - 2a 80 - 2b 80 - 2c 81 - 2f 83 - 30 83 - 31 83 - 32 83 - 33 83 - 34 83 - 37 105 - 38 105 - 3b 106 - 3c 106 - 3d 106 - 3e 106 - 42 86 - 43 86 - 44 86 - 45 86 - 46 86 - 47 86 - 48 86 - 49 86 - 4a 87 - 4b 87 - 4c 124 - 4d 124 - 50 125 - 51 125 - 54 128 - 55 128 - 56 90 - 57 90 - 58 90 - 59 90 - 5a 90 - 5b 90 - 5e 111 - 5f 111 - 62 112 - 63 112 - 64 112 - 65 112 - 69 93 - 6a 94 - 6b 94 - 6e 96 - 6f 96 - 75 97 - 7a 98 - 7e 102 - 7f 116 - 80 116 - 81 116 - 82 116 - 83 116 - 84 116 - 85 116 - 86 116 - 87 117 - 88 117 - 89 117 - 8a 117 - 8b 117 - 8e 118 - 8f 118 - 90 118 - 91 118 - 92 118 - 93 118 - 96 121 - 97 121 + 0 49 + 1 49 + 2 49 + 3 49 + 4 49 + 5 49 + 6 51 + 7 51 + 8 51 + 9 51 + a 51 + 24 53 + 25 53 + 26 53 + 27 53 + 28 53 + 29 53 + 2a 53 + 2b 53 + 2c 54 + 2f 56 + 30 56 + 31 56 + 32 56 + 33 56 + 34 56 + 42 59 + 43 59 + 44 59 + 45 59 + 46 59 + 47 59 + 48 59 + 49 59 + 4a 60 + 55 60 + 56 62 + 57 62 + 58 62 + 59 62 + 5a 62 + 5b 62 + 5e 65 + 5f 65 + 60 65 + 61 65 + 62 65 + 63 65 + 87 69 + 88 69 + 89 69 + 8a 69 + 8b 69 + 8c 69 + 8d 69 + 8e 69 + 8f 70 + 90 70 + 91 70 + 92 70 + 93 70 + 96 71 + 97 71 + 98 71 + 99 71 + 9a 71 + 9b 71 + 9e 74 + 9f 74 } method 'create (Ljava/io/File;)Ljava/util/Scanner;' { - 4 132 - 8 132 + 4 78 + 8 78 } } @@ -356,30 +268,32 @@ Lines mapping: 16 <-> 16 18 <-> 18 21 <-> 22 -25 <-> 41 -26 <-> 30 -28 <-> 32 -29 <-> 33 -31 <-> 35 -34 <-> 38 -36 <-> 59 -38 <-> 64 -39 <-> 65 -40 <-> 66 -42 <-> 69 -46 <-> 94 -47 <-> 79 -49 <-> 81 -50 <-> 82 -52 <-> 84 -55 <-> 87 -56 <-> 129 -58 <-> 91 -60 <-> 112 -62 <-> 117 -63 <-> 118 -64 <-> 119 -67 <-> 122 -71 <-> 133 +25 <-> 25 +26 <-> 27 +28 <-> 29 +29 <-> 30 +31 <-> 32 +34 <-> 35 +37 <-> 38 +40 <-> 42 +41 <-> 43 +42 <-> 44 +44 <-> 47 +48 <-> 50 +49 <-> 52 +51 <-> 54 +52 <-> 55 +54 <-> 57 +57 <-> 60 +58 <-> 61 +60 <-> 63 +63 <-> 66 +66 <-> 70 +67 <-> 71 +68 <-> 72 +71 <-> 75 +75 <-> 79 Not mapped: 20 +38 +64 diff --git a/testData/src/java16/pkg/TestTryWithResourcesSwitchJ16.java b/testData/src/java16/pkg/TestTryWithResourcesSwitchJ16.java index 1f5513bbb9..e81dcc95b7 100644 --- a/testData/src/java16/pkg/TestTryWithResourcesSwitchJ16.java +++ b/testData/src/java16/pkg/TestTryWithResourcesSwitchJ16.java @@ -33,6 +33,8 @@ public void test1(File f) throws FileNotFoundException { default: System.out.println("default"); } + + System.out.println("after switch"); } System.out.println("after"); @@ -57,6 +59,8 @@ public int test2(File f) throws FileNotFoundException { default: System.out.println("default"); } + + System.out.println("after switch"); } System.out.println("after"); From 6e20839805ca24526e8df846e0d5030f74245079 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Fri, 26 Nov 2021 00:19:55 -0500 Subject: [PATCH 46/85] Apply bytecode tracer changes --- .../modules/decompiler/exps/SwitchExprent.java | 14 ++++++-------- .../modules/decompiler/exps/SwitchHeadExprent.java | 7 ++++--- .../modules/decompiler/exps/YieldExprent.java | 4 ++-- 3 files changed, 12 insertions(+), 13 deletions(-) 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 e349d417bd..359bba6cb1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -33,8 +33,7 @@ public TextBuffer toJava(int indent) { VarType switchType = this.backing.getHeadexprentList().get(0).getExprType(); - buf.append(this.backing.getHeadexprentList().get(0).toJava(indent, tracer)).append(" {").appendLineSeparator(); - tracer.incrementCurrentSourceLine(); + buf.append(this.backing.getHeadexprentList().get(0).toJava(indent)).append(" {").appendLineSeparator(); for (int i = 0; i < this.backing.getCaseStatements().size(); i++) { Statement stat = this.backing.getCaseStatements().get(i); @@ -76,7 +75,7 @@ public TextBuffer toJava(int indent) { buf.append(((FieldExprent)value).getName()); } else { - buf.append(value.toJava(indent, tracer)); + buf.append(value.toJava(indent)); } hasEdge = true; @@ -96,6 +95,7 @@ public TextBuffer toJava(int indent) { simple = false; } + // Single yield or throw if (simple) { Exprent exprent = stat.getExprents().get(0); @@ -106,12 +106,12 @@ public TextBuffer toJava(int indent) { ((ConstExprent)content).setConstType(this.type); } - buf.append(content.toJava(indent, tracer).append(";")); + buf.append(content.toJava(indent).append(";")); } else if (exprent.type == Exprent.EXPRENT_EXIT) { ExitExprent exit = (ExitExprent) exprent; if (exit.getExitType() == ExitExprent.EXIT_THROW) { - buf.append(exit.toJava(indent, tracer).append(";")); + buf.append(exit.toJava(indent).append(";")); } else { throw new IllegalStateException("Can't have return in switch expression"); } @@ -119,14 +119,12 @@ public TextBuffer toJava(int indent) { } else { buf.append("{"); buf.appendLineSeparator(); - tracer.incrementCurrentSourceLine(); - TextBuffer statBuf = stat.toJava(indent + 2, tracer); + TextBuffer statBuf = stat.toJava(indent + 2); buf.append(statBuf); buf.appendIndent(indent + 1).append("}"); } buf.appendLineSeparator(); - tracer.incrementCurrentSourceLine(); } buf.appendIndent(indent).append("}"); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java index 48e117f7df..b7188d384c 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java @@ -73,9 +73,10 @@ public List getAllExprents(List lst) { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { - tracer.addMapping(bytecode); - return value.toJava(indent, tracer).enclose("switch(", ")"); + public TextBuffer toJava(int indent) { + TextBuffer buf = value.toJava(indent).enclose("switch(", ")"); + buf.addStartBytecodeMapping(bytecode); + return buf; } @Override diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java index d36cd08d78..a3eef2083a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java @@ -30,10 +30,10 @@ public Exprent copy() { } @Override - public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) { + public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); buf.append("yield "); - ExprProcessor.getCastedExprent(this.content, this.retType, buf, indent, false, false, false, false, tracer); + ExprProcessor.getCastedExprent(this.content, this.retType, buf, indent, false, false, false, false); return buf; } From 6208ded0274c3243c2c3b16244f4ea897d70666a Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Fri, 26 Nov 2021 00:51:42 -0500 Subject: [PATCH 47/85] Improve switch expression parsing --- .../decompiler/SwitchExpressionHelper.java | 71 ++++++++++------ .../decompiler/stats/BasicBlockStatement.java | 1 + .../pkg/TestReturnSwitchExpression4.dec | 84 +++++++++---------- 3 files changed, 84 insertions(+), 72 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java index f2cfbcc9eb..1f2fe1eaa1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java @@ -37,18 +37,24 @@ private static boolean processStatement(SwitchStatement stat) { VarVersionPair foundVar = null; VarExprent found = null; for (Statement caseStat : stat.getCaseStatements()) { - // Need to be basic blocks for now - if (caseStat.type != Statement.TYPE_BASICBLOCK) { - return false; - } - List exprents = caseStat.getExprents(); + // TODO: improve checking, possibly use SSA if (exprents != null && !exprents.isEmpty()) { Exprent exprent = exprents.get(exprents.size() - 1); if (exprent.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)exprent).getLeft().type == Exprent.EXPRENT_VAR) { VarVersionPair var = (((VarExprent) ((AssignmentExprent) exprent).getLeft())).getVarVersionPair(); + // We need all break edges to be enclosed in the current switch statement, as otherwise they could be breaking to statements beyond our scope, which messes up control flow + List breaks = caseStat.getSuccessorEdges(StatEdge.TYPE_BREAK); + if (breaks.isEmpty()) { + return false; // TODO: handle switch expression with fallthrough! + } + + if (breaks.get(0).closure != stat) { + return false; + } + if (foundVar == null) { foundVar = var; found = (((VarExprent) ((AssignmentExprent) exprent).getLeft())); @@ -80,32 +86,13 @@ private static boolean processStatement(SwitchStatement stat) { for (Statement st : stat.getCaseStatements()) { Map replacements = new HashMap<>(); - // No exprents, must not be a basicblock - if (st.getExprents() == null) { - continue; - } - - for (Exprent e : st.getExprents()) { - // Check for "var10000 = " within the exprents - if (e.type == Exprent.EXPRENT_ASSIGNMENT) { - AssignmentExprent assign = ((AssignmentExprent) e); - - if (assign.getLeft().type == Exprent.EXPRENT_VAR) { - if (((VarExprent)assign.getLeft()).getIndex() == foundVar.var) { - // Make yield with the right side of the assignment - replacements.put(assign, new YieldExprent(assign.getRight(), assign.getExprType())); - } - } - } - } + findReplacements(st, foundVar, replacements); // Replace exprents that we found if (!replacements.isEmpty()) { // Replace the assignments with yields, this allows 2 things: // 1) - for (Map.Entry entry : replacements.entrySet()) { - st.replaceExprent(entry.getKey(), entry.getValue()); - } + replace(st, replacements); } } @@ -126,6 +113,38 @@ private static boolean processStatement(SwitchStatement stat) { return false; } + private static void findReplacements(Statement stat, VarVersionPair var, Map replacements) { + if (stat.getExprents() != null) { + for (Exprent e : stat.getExprents()) { + // Check for "var10000 = " within the exprents + if (e.type == Exprent.EXPRENT_ASSIGNMENT) { + AssignmentExprent assign = ((AssignmentExprent) e); + + if (assign.getLeft().type == Exprent.EXPRENT_VAR) { + if (((VarExprent) assign.getLeft()).getIndex() == var.var) { + // Make yield with the right side of the assignment + replacements.put(assign, new YieldExprent(assign.getRight(), assign.getExprType())); + } + } + } + } + } + + for (Statement st : stat.getStats()) { + findReplacements(st, var, replacements); + } + } + + private static void replace(Statement stat, Map replacements) { + for (Map.Entry entry : replacements.entrySet()) { + stat.replaceExprent(entry.getKey(), entry.getValue()); + } + + for (Statement st : stat.getStats()) { + replace(st, replacements); + } + } + public static boolean hasSwitchExpressions(RootStatement statement) { return statement.mt.getBytecodeVersion().hasSwitchExpressions() && DecompilerContext.getOption(IFernflowerPreferences.SWITCH_EXPRESSIONS); } 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 b4744f59d9..55f36dc4b1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java @@ -123,6 +123,7 @@ public BasicBlock getBlock() { return block; } + // TODO: is this allowed? SecondaryFunctionsHelper says "only head expressions can be replaced!" @Override public void replaceExprent(Exprent oldexpr, Exprent newexpr) { for (int i = 0; i < this.exprents.size(); i++) { diff --git a/testData/results/pkg/TestReturnSwitchExpression4.dec b/testData/results/pkg/TestReturnSwitchExpression4.dec index 84558d594a..cc865bbc04 100644 --- a/testData/results/pkg/TestReturnSwitchExpression4.dec +++ b/testData/results/pkg/TestReturnSwitchExpression4.dec @@ -2,59 +2,51 @@ package pkg; public class TestReturnSwitchExpression4 { public String test(int i) { - String var10000; - switch(i) { - case 1: - var10000 = "1";// 6 - break; - case 2: - var10000 = "2";// 7 - break; - default: - if (i > 0) {// 9 - var10000 = "Unknown";// 10 - } else { - System.out.println("Negative");// 12 - var10000 = "Negative";// 13 + return switch(i) {// 5 + case 1 -> "1";// 6 + case 2 -> "2";// 7 + default -> { + if (i > 0) {// 9 + yield "Unknown";// 10 + } else { + System.out.println("Negative");// 12 + yield "Negative";// 13 + } } - } - - return var10000;// 5 + }; } } class 'pkg/TestReturnSwitchExpression4' { method 'test (I)Ljava/lang/String;' { - 0 5 - 1 5 - 1c 7 - 1d 7 - 1e 8 - 21 10 - 22 10 - 23 11 - 26 13 - 27 13 - 2a 14 - 2b 14 - 2f 16 - 30 16 - 31 16 - 32 16 - 33 16 - 34 16 - 35 16 - 36 16 - 37 17 - 39 21 + 0 4 + 1 4 + 1c 5 + 1d 5 + 21 6 + 22 6 + 26 8 + 27 8 + 2a 9 + 2b 9 + 2f 11 + 30 11 + 31 11 + 32 11 + 33 11 + 34 11 + 35 11 + 36 11 + 37 12 + 39 4 } } Lines mapping: -5 <-> 22 -6 <-> 8 -7 <-> 11 -9 <-> 14 -10 <-> 15 -12 <-> 17 -13 <-> 18 +5 <-> 5 +6 <-> 6 +7 <-> 7 +9 <-> 9 +10 <-> 10 +12 <-> 12 +13 <-> 13 From a66539795ec147ddf5a3713e40c0a1cd3865848b Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Fri, 26 Nov 2021 11:42:03 -0500 Subject: [PATCH 48/85] fix fallthrough detection, remove silent side effects from try with resources --- .../decompiler/SwitchExpressionHelper.java | 14 ++--- .../modules/decompiler/TryHelper.java | 6 +-- .../decompiler/exps/SwitchExprent.java | 6 ++- .../java/decompiler/SingleClassesTest.java | 1 + .../pkg/TestSwitchExpressionFallthrough1.dec | 53 +++++++++++++++++++ .../pkg/TestSwitchExpressionFallthrough1.java | 18 +++++++ 6 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 testData/results/pkg/TestSwitchExpressionFallthrough1.dec create mode 100644 testData/src/java16/pkg/TestSwitchExpressionFallthrough1.java diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java index 1f2fe1eaa1..2c810ba163 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java @@ -42,15 +42,15 @@ private static boolean processStatement(SwitchStatement stat) { if (exprents != null && !exprents.isEmpty()) { Exprent exprent = exprents.get(exprents.size() - 1); + // We need all break edges to be enclosed in the current switch statement, as otherwise they could be breaking to statements beyond our scope, which messes up control flow + List breaks = caseStat.getSuccessorEdges(StatEdge.TYPE_BREAK); + if (breaks.isEmpty()) { + return false; // TODO: handle switch expression with fallthrough! + } + if (exprent.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)exprent).getLeft().type == Exprent.EXPRENT_VAR) { VarVersionPair var = (((VarExprent) ((AssignmentExprent) exprent).getLeft())).getVarVersionPair(); - // We need all break edges to be enclosed in the current switch statement, as otherwise they could be breaking to statements beyond our scope, which messes up control flow - List breaks = caseStat.getSuccessorEdges(StatEdge.TYPE_BREAK); - if (breaks.isEmpty()) { - return false; // TODO: handle switch expression with fallthrough! - } - if (breaks.get(0).closure != stat) { return false; } @@ -102,7 +102,7 @@ private static boolean processStatement(SwitchStatement stat) { VarExprent vExpr = new VarExprent(found.getIndex(), found.getVarType(), found.getProcessor()); vExpr.setStack(true); // We want to inline - AssignmentExprent toAdd = new AssignmentExprent(vExpr, new SwitchExprent(stat, found.getExprType()), null); + AssignmentExprent toAdd = new AssignmentExprent(vExpr, new SwitchExprent(stat, found.getExprType(), false), null); exprents.add(0, toAdd); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java index c173da6b29..ef89512e4d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryHelper.java @@ -18,9 +18,9 @@ public static boolean enhanceTryStats(RootStatement root, StructClass cl) { boolean ret = makeTryWithResourceRec(cl, root); if (ret) { - if (!cl.getVersion().hasNewTryWithResources()) { - SequenceHelper.condenseSequences(root); + SequenceHelper.condenseSequences(root); + if (!cl.getVersion().hasNewTryWithResources()) { if (collapseTryRec(root)) { SequenceHelper.condenseSequences(root); } @@ -28,8 +28,6 @@ public static boolean enhanceTryStats(RootStatement root, StructClass cl) { } if (cl.getVersion().hasNewTryWithResources()) { - SequenceHelper.condenseSequences(root); - if (mergeTrys(root)) { SequenceHelper.condenseSequences(root); 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 359bba6cb1..02d53d1bb6 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -15,11 +15,13 @@ public class SwitchExprent extends Exprent { private final SwitchStatement backing; private final VarType type; + private final boolean fallthrough; - public SwitchExprent(SwitchStatement backing, VarType type) { + public SwitchExprent(SwitchStatement backing, VarType type, boolean fallthrough) { super(EXPRENT_SWITCH); this.backing = backing; this.type = type; + this.fallthrough = fallthrough; } @Override @@ -139,7 +141,7 @@ public VarType getExprType() { @Override public Exprent copy() { - return new SwitchExprent(this.backing, this.type); + return new SwitchExprent(this.backing, this.type, this.fallthrough); } @Override diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index dc0498159a..6e43d60fe1 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -344,6 +344,7 @@ private void registerDefault() { register(JAVA_16, "TestConstructorSwitchExpression1"); register(JAVA_16, "TestConstructorSwitchExpression2"); register(JAVA_16, "TestAssertSwitchExpression"); + register(JAVA_16, "TestSwitchExpressionFallthrough1"); register(JAVA_16_PREVIEW, "TestSealedClasses"); register(JAVA_16_PREVIEW, "PermittedSubClassA", "TestSealedClasses"); diff --git a/testData/results/pkg/TestSwitchExpressionFallthrough1.dec b/testData/results/pkg/TestSwitchExpressionFallthrough1.dec new file mode 100644 index 0000000000..70d7c69080 --- /dev/null +++ b/testData/results/pkg/TestSwitchExpressionFallthrough1.dec @@ -0,0 +1,53 @@ +package pkg; + +public class TestSwitchExpressionFallthrough1 { + public void test(int i) { + byte var10000; + switch(i) {// 5 + case 1: + System.out.println(i);// 7 + case 2: + case 3: + case 4: + var10000 = 2;// 11 + break; + default: + var10000 = 3;// 13 + } + + int j = var10000; + System.out.println(j);// 16 + }// 17 +} + +class 'pkg/TestSwitchExpressionFallthrough1' { + method 'test (I)V' { + 0 5 + 1 5 + 20 7 + 21 7 + 22 7 + 23 7 + 24 7 + 27 11 + 28 12 + 2b 14 + 2c 17 + 2d 18 + 2e 18 + 2f 18 + 30 18 + 31 18 + 32 18 + 33 18 + 34 19 + } +} + +Lines mapping: +5 <-> 6 +7 <-> 8 +11 <-> 12 +13 <-> 15 +16 <-> 19 +17 <-> 20 diff --git a/testData/src/java16/pkg/TestSwitchExpressionFallthrough1.java b/testData/src/java16/pkg/TestSwitchExpressionFallthrough1.java new file mode 100644 index 0000000000..949c97d117 --- /dev/null +++ b/testData/src/java16/pkg/TestSwitchExpressionFallthrough1.java @@ -0,0 +1,18 @@ +package pkg; + +public class TestSwitchExpressionFallthrough1 { + public void test(int i) { + int j = switch (i) { + case 1: + System.out.println(i); + case 2: + case 3: + case 4: + yield 2; + default: + yield 3; + }; + + System.out.println(j); + } +} From 7680f471a6e14228d6b52483927260a15b9a8966 Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Fri, 26 Nov 2021 21:32:08 +0100 Subject: [PATCH 49/85] Recursive lambda inlining test --- .../java/decompiler/SingleClassesTest.java | 1 + testData/src/jasm/TestRecursiveLambda.jasm | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 testData/src/jasm/TestRecursiveLambda.jasm diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 38e5a6facf..06e31b711e 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -185,6 +185,7 @@ private void registerDefault() { register(JAVA_8, "TestSuperInner", "TestSuperInnerBase"); register(JASM, "TestMissingConstructorCallGood"); register(JASM, "TestMissingConstructorCallBad"); + register(JASM, "TestRecursiveLambda"); register(JAVA_8, "TestEmptyBlocks"); register(JAVA_8, "TestInvertedFloatComparison"); register(JAVA_8, "TestPrivateEmptyConstructor"); diff --git a/testData/src/jasm/TestRecursiveLambda.jasm b/testData/src/jasm/TestRecursiveLambda.jasm new file mode 100644 index 0000000000..11de13f850 --- /dev/null +++ b/testData/src/jasm/TestRecursiveLambda.jasm @@ -0,0 +1,51 @@ +/** + * This code can be assembled with asmtools + * using asmtools jasm -g *.jasm command line. + */ +package pkg; + +super public class TestRecursiveLambda + version 52:0 +{ + + // weird fix + const #7 = Method TestRecursiveLambda.test:"()V"; + + public Method "":"()V" + stack 2 locals 2 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + + aload_0; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;":run:"(Lpkg/TestHashedNaming;)Ljava/lang/Runnable;" { + MethodType "()V", + MethodHandle REF_invokeVirtual:#7, + MethodType "()V" + }; + + astore_1; + + return; + } + + public synthetic Method test:"()V" + stack 2 locals 2 + { + aload_0; + invokedynamic InvokeDynamic REF_invokeStatic:Method + java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;":run:"(Lpkg/TestHashedNaming;)Ljava/lang/Runnable;" { + MethodType "()V", + MethodHandle REF_invokeVirtual:#7, + MethodType "()V" + }; + + astore_1; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + aload_1; + invokevirtual Method java/lang/Object.hashCode:"()I"; + invokevirtual Method java/io/PrintStream.println:"(I)V"; + + return; + } +} // end Class TestRecursiveLambda From 89ec9b0e2cfa53a609d680726aea33127a8436f3 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Fri, 26 Nov 2021 16:48:54 -0500 Subject: [PATCH 50/85] Improve switch expression inlining --- .../main/rels/MethodProcessorRunnable.java | 5 +- .../decompiler/SwitchExpressionHelper.java | 111 +++++++++++++----- .../decompiler/TryWithResourcesProcessor.java | 3 +- .../decompiler/stats/BasicBlockStatement.java | 2 +- .../decompiler/stats/SequenceStatement.java | 4 + .../modules/decompiler/stats/Statement.java | 4 + .../pkg/TestAssertSwitchExpression.dec | 58 ++++----- .../pkg/TestInlineSwitchExpression1.dec | 77 ++++++------ .../pkg/TestInlineSwitchExpression3.dec | 37 +++--- .../pkg/TestInlineSwitchExpression5.dec | 74 +++++------- .../pkg/TestReturnSwitchExpression2.dec | 58 ++++----- 11 files changed, 229 insertions(+), 204 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java index 44659bb27e..fa92d0ac29 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java +++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java @@ -11,10 +11,7 @@ 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.*; 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; @@ -307,8 +304,8 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe SequenceHelper.condenseSequences(root); // remove empty blocks decompileRecord.add("CondenseSequences_SS", root); + // If we have simplified switches, try to make switch expressions if (SwitchExpressionHelper.hasSwitchExpressions(root)) { - // Make last minute switch expressions if (SwitchExpressionHelper.processSwitchExpressions(root)) { decompileRecord.add("ProcessSwitchExpr_SS", root); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java index 2c810ba163..c866a96043 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java @@ -3,20 +3,26 @@ import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.modules.decompiler.exps.*; -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.SwitchStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.*; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public final class SwitchExpressionHelper { - public static boolean processSwitchExpressions(Statement stat) { + public static boolean processSwitchExpressions(Statement root) { + boolean ret = processSwitchExpressionsRec(root); + + if (ret) { + SequenceHelper.condenseSequences(root); + } + + return ret; + } + + private static boolean processSwitchExpressionsRec(Statement stat) { boolean ret = false; - for (Statement st : stat.getStats()) { - ret |= processSwitchExpressions(st); + for (Statement st : new ArrayList<>(stat.getStats())) { + ret |= processSwitchExpressionsRec(st); } if (stat.type == Statement.TYPE_SWITCH) { @@ -33,11 +39,20 @@ private static boolean processStatement(SwitchStatement stat) { // At this stage, there are no variable assignments // So we need to figure out which variable, if any, this switch statement is an expression of and make it generate. - VarVersionPair foundVar = null; VarExprent found = null; for (Statement caseStat : stat.getCaseStatements()) { + Set edges = new HashSet<>(); + TryWithResourcesProcessor.findEdgesLeaving(caseStat, caseStat, edges); + for (StatEdge edge : edges) { + // There's a continue- can't be a switch expression + if (edge.getType() == StatEdge.TYPE_CONTINUE) { + return false; + } + } + List exprents = caseStat.getExprents(); + // TODO: improve checking, possibly use SSA if (exprents != null && !exprents.isEmpty()) { Exprent exprent = exprents.get(exprents.size() - 1); @@ -80,35 +95,75 @@ private static boolean processStatement(SwitchStatement stat) { if (!sucs.isEmpty()) { Statement suc = sucs.get(0).getDestination(); - if (suc.type == Statement.TYPE_BASICBLOCK) { // TODO: make basic block if it isn't found - stat.setPhantom(true); + if (suc.type != Statement.TYPE_BASICBLOCK) { // make basic block if it isn't found + Statement oldSuc = suc; - for (Statement st : stat.getCaseStatements()) { - Map replacements = new HashMap<>(); + suc = BasicBlockStatement.create(); + SequenceStatement seq = new SequenceStatement(stat, suc); + + seq.setParent(stat.getParent()); - findReplacements(st, foundVar, replacements); + stat.replaceWith(seq); - // Replace exprents that we found - if (!replacements.isEmpty()) { - // Replace the assignments with yields, this allows 2 things: - // 1) - replace(st, replacements); + seq.setAllParent(); + + // Replace successors with the new basic block + for (Statement st : stat.getCaseStatements()) { + for (StatEdge edge : st.getAllSuccessorEdges()) { + if (edge.getDestination() == oldSuc) { + st.removeSuccessor(edge); + + st.addSuccessor(new StatEdge(edge.getType(), st, suc, seq)); + } } } - // TODO: move exprents from switch head to successor + // Control flow from new basic block to the next one + suc.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, suc, oldSuc, seq)); + } - List exprents = suc.getExprents(); + stat.setPhantom(true); - VarExprent vExpr = new VarExprent(found.getIndex(), found.getVarType(), found.getProcessor()); - vExpr.setStack(true); // We want to inline - AssignmentExprent toAdd = new AssignmentExprent(vExpr, new SwitchExprent(stat, found.getExprType(), false), null); + for (Statement st : stat.getCaseStatements()) { + Map replacements = new HashMap<>(); - exprents.add(0, toAdd); + findReplacements(st, foundVar, replacements); - return true; + // Replace exprents that we found + if (!replacements.isEmpty()) { + // Replace the assignments with yields, this allows 2 things: + // 1) Not having to replace the assignments later on + // 2) Preventing the variable assignment tracker from putting variable definitions too early because the assignments are no longer in the phantom statement + replace(st, replacements); + } } - } + + List exprents = suc.getExprents(); + + VarExprent vExpr = new VarExprent(found.getIndex(), found.getVarType(), found.getProcessor()); + vExpr.setStack(true); // We want to inline + AssignmentExprent toAdd = new AssignmentExprent(vExpr, new SwitchExprent(stat, found.getExprType(), false), null); + + exprents.add(0, toAdd); + + // move exprents from switch head to successor + List firstExprents = stat.getFirst().getExprents(); + if (firstExprents != null && !firstExprents.isEmpty()) { + int i = 0; + for (Iterator iterator = firstExprents.iterator(); iterator.hasNext(); ) { + Exprent ex = iterator.next(); + if (ex.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent) ex).getLeft().type == Exprent.EXPRENT_VAR) { + if (((VarExprent) ((AssignmentExprent) ex).getLeft()).isStack()) { + exprents.add(i, ex); + i++; + iterator.remove(); + } + } + } + } + + return true; + } return false; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java index 878bb73597..524697cb60 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/TryWithResourcesProcessor.java @@ -304,7 +304,8 @@ private static Set findExitpoints(Statement stat) { return edges.stream().map(StatEdge::getDestination).collect(Collectors.toSet()); } - private static void findEdgesLeaving(Statement curr, Statement check, Set edges) { + // TODO: move to better place + public static void findEdgesLeaving(Statement curr, Statement check, Set edges) { for (StatEdge edge : curr.getAllSuccessorEdges()) { if (!check.containsStatement(edge.getDestination()) && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) { edges.add(edge); 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 55f36dc4b1..cbecd8cb77 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java @@ -85,7 +85,7 @@ public Statement getSimpleCopy() { // TODO: cache this? @Override public List getImplicitlyDefinedVars() { - if (getExprents().size() > 0) { + if (getExprents() != null && getExprents().size() > 0) { List vars = new ArrayList<>(); List exps = getExprents(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java index 0749cdf86d..1aecb21cd0 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java @@ -21,6 +21,10 @@ private SequenceStatement() { type = Statement.TYPE_SEQUENCE; } + public SequenceStatement(Statement... stats) { + this(Arrays.asList(stats)); + } + public SequenceStatement(List lst) { this(); 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 dbc7faa4ae..73382a0e34 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java @@ -511,6 +511,10 @@ public void initSimpleCopy() { } } + public final void replaceWith(Statement stat) { + this.parent.replaceStatement(this, stat); + } + public final void destroy() { this.parent.replaceStatement(this, BasicBlockStatement.create()); } diff --git a/testData/results/pkg/TestAssertSwitchExpression.dec b/testData/results/pkg/TestAssertSwitchExpression.dec index 445893b8f1..73fc99dd12 100644 --- a/testData/results/pkg/TestAssertSwitchExpression.dec +++ b/testData/results/pkg/TestAssertSwitchExpression.dec @@ -3,19 +3,11 @@ package pkg; public class TestAssertSwitchExpression { public void test(int i, String s) { if (!$assertionsDisabled) { - String var10001; - switch(i) { - case 1: - var10001 = "1";// 6 - break; - case 2: - var10001 = "2";// 7 - break; - default: - var10001 = "Unknown";// 8 - } - - if (!s.equals(var10001)) {// 5 + if (!s.equals(switch(i) {// 5 + case 1 -> "1";// 6 + case 2 -> "2";// 7 + default -> "Unknown";// 8 + })) { throw new AssertionError(); } } @@ -29,28 +21,26 @@ class 'pkg/TestAssertSwitchExpression' { 1 4 2 4 3 4 - 6 17 - 7 6 - 8 6 - 24 8 - 25 8 - 26 9 - 29 11 - 2a 11 - 2b 12 - 2e 14 - 30 17 - 31 17 - 32 17 - 33 17 - 3d 18 - 3e 22 + 6 5 + 7 5 + 8 5 + 24 6 + 25 6 + 29 7 + 2a 7 + 2e 8 + 30 5 + 31 5 + 32 5 + 33 5 + 3d 10 + 3e 14 } } Lines mapping: -5 <-> 18 -6 <-> 9 -7 <-> 12 -8 <-> 15 -10 <-> 23 +5 <-> 6 +6 <-> 7 +7 <-> 8 +8 <-> 9 +10 <-> 15 diff --git a/testData/results/pkg/TestInlineSwitchExpression1.dec b/testData/results/pkg/TestInlineSwitchExpression1.dec index ef6b9f78a8..2792dd25e5 100644 --- a/testData/results/pkg/TestInlineSwitchExpression1.dec +++ b/testData/results/pkg/TestInlineSwitchExpression1.dec @@ -1,13 +1,10 @@ package pkg; import ext.Direction; -import java.io.PrintStream; public class TestInlineSwitchExpression1 { public void test(Direction direction) { - PrintStream var10000 = System.out;// 7 - - var10000.println(switch(direction) { + System.out.println(switch(direction) {// 7 case NORTH -> Direction.SOUTH;// 9 case SOUTH -> Direction.NORTH;// 11 case EAST -> Direction.WEST;// 13 @@ -21,43 +18,43 @@ public class TestInlineSwitchExpression1 { class 'pkg/TestInlineSwitchExpression1' { method 'test (Lext/Direction;)V' { - 0 7 - 1 7 - 2 7 - 6 9 - b 9 - 30 10 - 31 10 - 32 10 - 36 11 - 37 11 - 38 11 - 3c 12 - 3d 12 - 3e 12 - 42 13 - 43 13 - 44 13 - 48 14 - 49 14 - 4a 14 - 4e 15 - 4f 15 - 50 15 - 5b 16 - 5c 9 - 5d 9 - 5e 9 - 5f 18 + 0 6 + 1 6 + 2 6 + 6 6 + b 6 + 30 7 + 31 7 + 32 7 + 36 8 + 37 8 + 38 8 + 3c 9 + 3d 9 + 3e 9 + 42 10 + 43 10 + 44 10 + 48 11 + 49 11 + 4a 11 + 4e 12 + 4f 12 + 50 12 + 5b 13 + 5c 6 + 5d 6 + 5e 6 + 5f 15 } } Lines mapping: -7 <-> 8 -9 <-> 11 -11 <-> 12 -13 <-> 13 -15 <-> 14 -17 <-> 15 -19 <-> 16 -21 <-> 19 +7 <-> 7 +9 <-> 8 +11 <-> 9 +13 <-> 10 +15 <-> 11 +17 <-> 12 +19 <-> 13 +21 <-> 16 diff --git a/testData/results/pkg/TestInlineSwitchExpression3.dec b/testData/results/pkg/TestInlineSwitchExpression3.dec index 2fabd1260a..4bf1425264 100644 --- a/testData/results/pkg/TestInlineSwitchExpression3.dec +++ b/testData/results/pkg/TestInlineSwitchExpression3.dec @@ -1,13 +1,10 @@ package pkg; import ext.Direction; -import java.io.PrintStream; public class TestInlineSwitchExpression3 { public void test(Direction direction) { - PrintStream var10000 = System.out;// 9 - - var10000.println(switch(direction) { + System.out.println(switch(direction) {// 9 case NORTH, EAST, UP -> -1;// 13 case SOUTH, WEST, DOWN -> 1;// 17 default -> throw new IncompatibleClassChangeError(); @@ -17,23 +14,23 @@ public class TestInlineSwitchExpression3 { class 'pkg/TestInlineSwitchExpression3' { method 'test (Lext/Direction;)V' { - 0 7 - 1 7 - 2 7 - 6 9 - b 9 - 30 10 - 34 11 - 3f 12 - 40 9 - 41 9 - 42 9 - 43 14 + 0 6 + 1 6 + 2 6 + 6 6 + b 6 + 30 7 + 34 8 + 3f 9 + 40 6 + 41 6 + 42 6 + 43 11 } } Lines mapping: -9 <-> 8 -13 <-> 11 -17 <-> 12 -19 <-> 15 +9 <-> 7 +13 <-> 8 +17 <-> 9 +19 <-> 12 diff --git a/testData/results/pkg/TestInlineSwitchExpression5.dec b/testData/results/pkg/TestInlineSwitchExpression5.dec index be9634c7b8..157b9c69f6 100644 --- a/testData/results/pkg/TestInlineSwitchExpression5.dec +++ b/testData/results/pkg/TestInlineSwitchExpression5.dec @@ -5,19 +5,11 @@ public class TestInlineSwitchExpression5 { int j = 0;// 5 while(true) { - byte var10001; - switch(i) { - case 1: - var10001 = 4;// 7 - break; - case 2: - var10001 = 8;// 8 - break; - default: - var10001 = 5;// 9 - } - - if (j >= var10001) {// 6 + if (j >= switch(i) {// 6 + case 1 -> 4;// 7 + case 2 -> 8;// 8 + default -> 5;// 9 + }) { return;// 15 } @@ -31,37 +23,35 @@ class 'pkg/TestInlineSwitchExpression5' { method 'test (I)V' { 0 4 1 4 - 2 19 - 3 8 - 4 8 - 20 10 - 21 11 - 24 13 - 25 13 - 26 14 - 29 16 - 2a 19 - 2d 23 - 2e 23 - 2f 23 - 30 24 - 31 24 - 32 24 - 33 24 - 34 24 - 35 24 - 36 24 - 37 24 - 3b 20 + 2 7 + 3 7 + 4 7 + 20 8 + 24 9 + 25 9 + 29 10 + 2a 7 + 2d 15 + 2e 15 + 2f 15 + 30 16 + 31 16 + 32 16 + 33 16 + 34 16 + 35 16 + 36 16 + 37 16 + 3b 12 } } Lines mapping: 5 <-> 5 -6 <-> 20 -7 <-> 11 -8 <-> 14 -9 <-> 17 -11 <-> 24 -13 <-> 25 -15 <-> 21 +6 <-> 8 +7 <-> 9 +8 <-> 10 +9 <-> 11 +11 <-> 16 +13 <-> 17 +15 <-> 13 diff --git a/testData/results/pkg/TestReturnSwitchExpression2.dec b/testData/results/pkg/TestReturnSwitchExpression2.dec index 33130248ac..832d0fc308 100644 --- a/testData/results/pkg/TestReturnSwitchExpression2.dec +++ b/testData/results/pkg/TestReturnSwitchExpression2.dec @@ -2,19 +2,11 @@ package pkg; public class TestReturnSwitchExpression2 { public String test(int i) { - byte var10000; - switch(i) { - case 1: - var10000 = 2;// 6 - break; - case 2: - var10000 = 1;// 7 - break; - default: - var10000 = 3;// 8 - } - - return switch(var10000) {// 5 + return switch(switch(i) {// 5 + case 1 -> 2;// 6 + case 2 -> 1;// 7 + default -> 3;// 8 + }) { case 1 -> "1";// 10 case 2 -> "2";// 11 default -> "Unknown";// 12 @@ -24,28 +16,26 @@ public class TestReturnSwitchExpression2 { class 'pkg/TestReturnSwitchExpression2' { method 'test (I)Ljava/lang/String;' { - 0 5 - 1 5 - 1c 7 - 1d 8 - 20 10 - 21 11 - 24 13 - 25 16 - 40 17 - 41 17 - 45 18 - 46 18 - 4a 19 - 4c 16 + 0 4 + 1 4 + 1c 5 + 20 6 + 24 7 + 25 4 + 40 9 + 41 9 + 45 10 + 46 10 + 4a 11 + 4c 4 } } Lines mapping: -5 <-> 17 -6 <-> 8 -7 <-> 11 -8 <-> 14 -10 <-> 18 -11 <-> 19 -12 <-> 20 +5 <-> 5 +6 <-> 6 +7 <-> 7 +8 <-> 8 +10 <-> 10 +11 <-> 11 +12 <-> 12 From 100bb811c9cf8eefe86318472acfe1c696840094 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Fri, 26 Nov 2021 22:13:59 -0500 Subject: [PATCH 51/85] Fix eclipse compiler switch-on-enum resugaring --- .../java/decompiler/main/ClassWriter.java | 8 +++ .../modules/decompiler/SwitchHelper.java | 64 ++++++++++++++----- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index b9cbb1aa51..c5278651d8 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -11,6 +11,7 @@ import org.jetbrains.java.decompiler.main.rels.ClassWrapper; import org.jetbrains.java.decompiler.main.rels.MethodWrapper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; +import org.jetbrains.java.decompiler.modules.decompiler.SwitchHelper; import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; @@ -58,6 +59,13 @@ private static void invokeProcessors(ClassNode node) { ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); + // Very late switch processing, needs entire class to be decompiled for eclipse switchmap style switch-on-enum + for (MethodWrapper method : wrapper.getMethods()) { + if (method.root != null) { + SwitchHelper.simplifySwitches(method.root, method.methodStruct); + } + } + InitializerProcessor.extractInitializers(wrapper); InitializerProcessor.hideInitalizers(wrapper); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java index 2c03044ae8..d8dfaef47d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java @@ -11,6 +11,7 @@ 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.SwitchStatement; +import org.jetbrains.java.decompiler.struct.StructClass; import org.jetbrains.java.decompiler.struct.StructField; import org.jetbrains.java.decompiler.struct.StructMethod; @@ -47,23 +48,49 @@ private static boolean simplify(SwitchStatement switchStatement, StructMethod mt List> caseValues = switchStatement.getCaseValues(); Map mapping = new HashMap<>(caseValues.size()); ArrayExprent array = (ArrayExprent)value; - FieldExprent arrayField = (FieldExprent)array.getArray(); - ClassesProcessor.ClassNode classNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(arrayField.getClassname()); - if (classNode != null) { - ClassWrapper classWrapper = classNode.getWrapper(); - if (classWrapper != null) { - MethodWrapper wrapper = classWrapper.getMethodWrapper(CodeConstants.CLINIT_NAME, "()V"); - if (wrapper != null && wrapper.root != null) { - wrapper.getOrBuildGraph().iterateExprents(exprent -> { - if (exprent instanceof AssignmentExprent) { - AssignmentExprent assignment = (AssignmentExprent) exprent; - Exprent left = assignment.getLeft(); - if (left.type == Exprent.EXPRENT_ARRAY && ((ArrayExprent) left).getArray().equals(arrayField)) { - mapping.put(assignment.getRight(), ((InvocationExprent) ((ArrayExprent) left).getIndex()).getInstance()); + if (array.getArray().type == Exprent.EXPRENT_FIELD) { + FieldExprent arrayField = (FieldExprent) array.getArray(); + ClassesProcessor.ClassNode classNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(arrayField.getClassname()); + if (classNode != null) { + ClassWrapper classWrapper = classNode.getWrapper(); + if (classWrapper != null) { + MethodWrapper wrapper = classWrapper.getMethodWrapper(CodeConstants.CLINIT_NAME, "()V"); + if (wrapper != null && wrapper.root != null) { + wrapper.getOrBuildGraph().iterateExprents(exprent -> { + if (exprent instanceof AssignmentExprent) { + AssignmentExprent assignment = (AssignmentExprent) exprent; + Exprent left = assignment.getLeft(); + if (left.type == Exprent.EXPRENT_ARRAY && ((ArrayExprent) left).getArray().equals(arrayField)) { + mapping.put(assignment.getRight(), ((InvocationExprent) ((ArrayExprent) left).getIndex()).getInstance()); + } } - } - return 0; - }); + return 0; + }); + } + } + } + } else { // Invocation + InvocationExprent invocation = (InvocationExprent) array.getArray(); + ClassesProcessor.ClassNode classNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(invocation.getClassname()); + if (classNode != null) { + ClassWrapper classWrapper = classNode.getWrapper(); + if (classWrapper != null) { + MethodWrapper wrapper = classWrapper.getMethodWrapper(invocation.getName(), "()[I"); + if (wrapper != null && wrapper.root != null) { + wrapper.getOrBuildGraph().iterateExprents(exprent -> { + if (exprent instanceof AssignmentExprent) { + AssignmentExprent assignment = (AssignmentExprent) exprent; + Exprent left = assignment.getLeft(); + if (left.type == Exprent.EXPRENT_ARRAY) { + mapping.put(assignment.getRight(), ((InvocationExprent) ((ArrayExprent) left).getIndex()).getInstance()); + } + } + return 0; + }); + } + } else { + // Need to wait til last minute processing + return false; } } } @@ -195,6 +222,11 @@ private static boolean isEnumArray(Exprent exprent) { //Exprent init = classNode.getWrapper().getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor().descriptorString)); //Above is null because we haven't preocess the class yet? } + } else if (tmp.type == Exprent.EXPRENT_INVOCATION) { + InvocationExprent inv = (InvocationExprent) tmp; + if (inv.getName().startsWith("$SWITCH_TABLE$")) { // More nonstandard behavior. Seems like eclipse compiler stuff: https://bugs.eclipse.org/bugs/show_bug.cgi?id=544521 TODO: needs tests! + return true; + } } } return false; From 6db1d3dc1202667cd03ac432edd7085f4b12728b Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sat, 27 Nov 2021 12:47:33 -0500 Subject: [PATCH 52/85] Add eclipse switch tests --- .../java/decompiler/SingleClassesTest.java | 2 +- .../custom/TestEclipseSwitchEnum.class | Bin 0 -> 1595 bytes .../custom/TestEclipseSwitchString.class | Bin 0 -> 1547 bytes .../custom/source/TestEclipseSwitchEnum.java | 22 +++++ .../source/TestEclipseSwitchString.java | 86 ++++++++++++++++++ testData/results/TestEclipseSwitchEnum.dec | 62 +++++++++++++ .../TestSwitchStringHashcodeCollision.java | 1 + 7 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 testData/classes/custom/TestEclipseSwitchEnum.class create mode 100644 testData/classes/custom/TestEclipseSwitchString.class create mode 100644 testData/classes/custom/source/TestEclipseSwitchEnum.java create mode 100644 testData/classes/custom/source/TestEclipseSwitchString.java create mode 100644 testData/results/TestEclipseSwitchEnum.dec diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 38e5a6facf..2d5a4407f2 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -423,7 +423,6 @@ private void registerDefault() { // TODO: Returns not processing properly registerRaw(CUSTOM, "TestJsr2"); register(JAVA_8, "TestOverrideIndirect"); - // TODO: IdeaNotNullHelper doesn't seem to be doing anything registerRaw(CUSTOM, "TestIdeaNotNull"); // TODO: Synchronized blocks don't work properly registerRaw(CUSTOM, "TestHotjava"); @@ -440,6 +439,7 @@ private void registerDefault() { // TODO: return not condensed properly and throw is not put into finally register(JAVA_8, "TestFinallyThrow"); register(JAVA_8, "TestWhile1"); + registerRaw(CUSTOM, "TestEclipseSwitchEnum"); } private void registerEntireClassPath() { diff --git a/testData/classes/custom/TestEclipseSwitchEnum.class b/testData/classes/custom/TestEclipseSwitchEnum.class new file mode 100644 index 0000000000000000000000000000000000000000..069a59f67b0e548768010d68a192c67f2364bdba GIT binary patch literal 1595 zcmaJ=-%}b_6#gzOEUue`kZKe(X;TsbjWkKqv_h;xp%PIuvqp#Up|j%FY_bBgEa~{v zzoCCcX8L4tCUN@1=~Eu^N45R#f{{)w%3(ADbTg%mFB|~6pXK0Q{o@^VowVsp=m zAf!PcrsEnu5(ww}knvRYybQy0?Z$qtlHM92c3ejY;RsY|OzKdj5s}7}jtIi?bVJ7| zbb%{XyJ4+&4t6bf)7*6|4MD`1+M{|zrG_w0Z%JZF9V56+k5qc6A}?liq>vU+o9>?7 zFde^|$_Qq0SH+w_bb$6@+p`XI%p*%wv%`#Iy{hbH_9;v9SeRuVzar4 zX6sNOGni*%_k~sWa+QI$oL#Xmq~|Bw_+B78=+2+KJ?+#Fs`SU}HTg)xpBc~w$zM-W_Ik*6K&aA(4T!E-2sdJCZ zp(QfRF}{S$^t(dKg2EM8{tcoQiw57~>M_QAoA2XVnJ#*CWM#e`7{ zb&)WRG5rgJ2;Afv^Fu035<;BmW=Jp~|AGCKH)%`CYG!uoEj~VX3=;r834DTEeejQT z4e+*jf=_4P;LiNdH27QK*FytSJkRjE-$f=CeS^4#C=n=2 zl9J3(lq}_VL^&346$SGAg0EpHNljCUV!!)j=2?+s&gj#%)nMkdmX~s@1rsOuYVL?H zJq3D&u&pvm>gO5h&al4QI$rl26+(n`G4$9H?3BEb~U0cmi zd3_dT4pG1fg+`ri%_{!sBO99g_{Hnh@^xlF~*@zU|?t~oob9LSN;d% z$_)$I=mHZL{s4cHA;$MiFI>c=iHq-?GjqQ0yw7>R^Yi!j9{@%$slXx7lHK2lZsuu{88>(EH=C~ykY?`f~JsHvrQqHEiGddd>0zHOup>#jgmU;n0nb3XGz zccTh59=K2~P`6^F^@sU`ZT)aV+ctHkSX2;b>RUNGt)Ma8zwCw&^$O}PXccxnXn~1eC0-HPe@vO4p`w z-lV0a_E)uR(IuC3DW)Pq)`Wol8CMbIa!EJM3{R37OEe=zGv+g5V$fg_OA_=yOWvxVM<>#WV>4BC9il8!}7N11byNY0u-*;agGYV+Bgf&u7Ph* zzi`1*Im&IYK%f>LjxzN<9QF~5gHKjZ;Qh>Bh%y|E7$d}pGkPNa#uGGsKFyQAhRNGS-fr^t;wim*hM~WCm4dUk z%Diujywm4+yXYVvhC0L9AMwX*$C@MlL}k{+D4t+DM%e2yjAH_mn6goPaGfGZ>l#We z9xa1dMUcsgL40SuJDO3I_@EP*^pvq#!2qL#2+DK4N?FA literal 0 HcmV?d00001 diff --git a/testData/classes/custom/source/TestEclipseSwitchEnum.java b/testData/classes/custom/source/TestEclipseSwitchEnum.java new file mode 100644 index 0000000000..08b978935e --- /dev/null +++ b/testData/classes/custom/source/TestEclipseSwitchEnum.java @@ -0,0 +1,22 @@ +package pkg; + +// Compiled with ecj 3.16.0 +public enum TestEclipseSwitchEnum { + A, + B, + C; + + public void test(TestEclipseSwitchEnum e) { + switch (e) { + case A: + System.out.println("A"); + break; + case B: + System.out.println("B"); + break; + case C: + System.out.println("C"); + break; + } + } +} diff --git a/testData/classes/custom/source/TestEclipseSwitchString.java b/testData/classes/custom/source/TestEclipseSwitchString.java new file mode 100644 index 0000000000..2e3d2358b6 --- /dev/null +++ b/testData/classes/custom/source/TestEclipseSwitchString.java @@ -0,0 +1,86 @@ +package pkg; + +// Compiled with ecj 3.16.0 +public class TestEclipseSwitchString { + public int test(String s) { + switch (s) { + default: + System.out.println("Test"); + break; + case "1": + return 1; + case "2": + return 2; + } + + return 0; + } + + public int test1(String s) { + switch (s) { + default: + System.out.println("Test"); + break; + case "1": + return 1; + case "2": + case "3": + return 2; + } + + return 0; + } + + public int test2(String s) { + switch (s) { + default: + System.out.println("Test"); + break; + case "1": + System.out.println("Hello"); + case "2": + case "3": + return 2; + } + + return 0; + } + + public int testHashcodeCollision(String s) { + switch (s) { + default: + System.out.println("Test"); + break; + case "BB": + return 1; + case "Aa": + return 2; + } + return 0; + } + + public int testHashcodeCollision1(String s) { + switch (s) { + default: + System.out.println("Test"); + break; + case "BB": + case "Aa": + return 2; + } + return 0; + } + + public int testHashcodeCollision2(String s) { + switch (s) { + default: + System.out.println("Test"); + break; + case "BB": + System.out.println("BB"); + case "Aa": + return 2; + } + return 0; + } +} diff --git a/testData/results/TestEclipseSwitchEnum.dec b/testData/results/TestEclipseSwitchEnum.dec new file mode 100644 index 0000000000..eecc626f22 --- /dev/null +++ b/testData/results/TestEclipseSwitchEnum.dec @@ -0,0 +1,62 @@ +package pkg; + +public enum TestEclipseSwitchEnum { + A, + B, + C; + + public void test(TestEclipseSwitchEnum var1) { + switch(var1) {// 9 + case A: + System.out.println("A");// 11 + break;// 12 + case B: + System.out.println("B");// 14 + break;// 15 + case C: + System.out.println("C");// 17 + } + + }// 20 +} + +class 'pkg/TestEclipseSwitchEnum' { + method 'test (Lpkg/TestEclipseSwitchEnum;)V' { + 3 8 + 8 8 + 24 10 + 25 10 + 26 10 + 27 10 + 28 10 + 29 10 + 2a 10 + 2b 10 + 2c 11 + 2f 13 + 30 13 + 31 13 + 32 13 + 33 13 + 34 13 + 35 13 + 36 13 + 37 14 + 3a 16 + 3b 16 + 3c 16 + 3d 16 + 3e 16 + 3f 16 + 42 19 + } +} + +Lines mapping: +9 <-> 9 +11 <-> 11 +12 <-> 12 +14 <-> 14 +15 <-> 15 +17 <-> 17 +20 <-> 20 diff --git a/testData/src/java8/pkg/TestSwitchStringHashcodeCollision.java b/testData/src/java8/pkg/TestSwitchStringHashcodeCollision.java index 9002367250..54e75913ee 100644 --- a/testData/src/java8/pkg/TestSwitchStringHashcodeCollision.java +++ b/testData/src/java8/pkg/TestSwitchStringHashcodeCollision.java @@ -1,5 +1,6 @@ package pkg; +// Adapted from CFR public class TestSwitchStringHashcodeCollision { public int test(String s) { switch (s) { From db609c486dd942837292790a6d5f41409322203f Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sat, 27 Nov 2021 12:50:00 -0500 Subject: [PATCH 53/85] Update TestSwitchStringHashcodeCollision.dec --- .../pkg/TestSwitchStringHashcodeCollision.dec | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/testData/results/pkg/TestSwitchStringHashcodeCollision.dec b/testData/results/pkg/TestSwitchStringHashcodeCollision.dec index 9387ad4343..6f3ca462e9 100644 --- a/testData/results/pkg/TestSwitchStringHashcodeCollision.dec +++ b/testData/results/pkg/TestSwitchStringHashcodeCollision.dec @@ -2,15 +2,15 @@ package pkg; public class TestSwitchStringHashcodeCollision { public int test(String s) { - switch(s) {// 5 + switch(s) {// 6 case "BB": - return 1;// 10 + return 1;// 11 case "Aa": case "FRED": - return 2;// 13 + return 2;// 14 default: - System.out.println("Test");// 7 - return 0;// 8 15 + System.out.println("Test");// 8 + return 0;// 9 16 } } } @@ -45,9 +45,9 @@ class 'pkg/TestSwitchStringHashcodeCollision' { } Lines mapping: -5 <-> 5 -7 <-> 12 -8 <-> 13 -10 <-> 7 -13 <-> 10 -15 <-> 13 +6 <-> 5 +8 <-> 12 +9 <-> 13 +11 <-> 7 +14 <-> 10 +16 <-> 13 From f36c773e395aa0b6b56532cb09e3ef3906ec7fad Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sat, 27 Nov 2021 14:44:41 -0500 Subject: [PATCH 54/85] Protect more processing in try-catch --- .../java/decompiler/main/ClassWriter.java | 60 ++++++++++++++----- .../decompiler/main/ClassesProcessor.java | 42 +++++++++++-- 2 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index c5278651d8..a9f2c49c03 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -53,35 +53,59 @@ public ClassWriter() { javadocProvider = (IFabricJavadocProvider) DecompilerContext.getProperty(IFabricJavadocProvider.PROPERTY_NAME); } - private static void invokeProcessors(ClassNode node) { - // TODO: need to wrap around with try catch as failure here can break the entire class - + private static boolean invokeProcessors(TextBuffer buffer, ClassNode node) { ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); // Very late switch processing, needs entire class to be decompiled for eclipse switchmap style switch-on-enum for (MethodWrapper method : wrapper.getMethods()) { if (method.root != null) { - SwitchHelper.simplifySwitches(method.root, method.methodStruct); + try { + SwitchHelper.simplifySwitches(method.root, method.methodStruct); + } catch (Throwable e) { + DecompilerContext.getLogger().writeMessage("Method " + method.methodStruct.getName() + " " + method.methodStruct.getDescriptor() + " in class " + node.classStruct.qualifiedName + " couldn't be written.", + IFernflowerLogger.Severity.WARN, + e); + method.decompileError = e; + } } } - InitializerProcessor.extractInitializers(wrapper); - InitializerProcessor.hideInitalizers(wrapper); + try { + InitializerProcessor.extractInitializers(wrapper); + InitializerProcessor.hideInitalizers(wrapper); - if (node.type == ClassNode.CLASS_ROOT && + if (node.type == ClassNode.CLASS_ROOT && cl.getVersion().has14ClassReferences() && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4)) { - ClassReference14Processor.processClassReferences(node); - } + ClassReference14Processor.processClassReferences(node); + } - if (cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM)) { - EnumProcessor.clearEnum(wrapper); - } + if (cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM)) { + EnumProcessor.clearEnum(wrapper); + } - if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ASSERTIONS)) { - AssertProcessor.buildAssertions(node); + if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ASSERTIONS)) { + AssertProcessor.buildAssertions(node); + } + } catch (Throwable t) { + DecompilerContext.getLogger().writeMessage("Class " + node.simpleName + " couldn't be written.", + IFernflowerLogger.Severity.WARN, + t); + buffer.append("// $FF: Couldn't be decompiled"); + buffer.appendLineSeparator(); + List lines = new ArrayList<>(); + collectErrorLines(t, lines); + for (String line : lines) { + buffer.append("//"); + if (!line.isEmpty()) buffer.append(' ').append(line); + buffer.appendLineSeparator(); + } + + return false; } + + return true; } public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_object, int indent) { @@ -225,7 +249,11 @@ public void classToJava(ClassNode node, TextBuffer buffer, int indent) { try { // last minute processing - invokeProcessors(node); + boolean ok = invokeProcessors(buffer, node); + + if (!ok) { + return; + } ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); @@ -1087,7 +1115,7 @@ private static void dumpError(TextBuffer buffer, MethodWrapper wrapper, int inde } } - private static void collectErrorLines(Throwable error, List lines) { + public static void collectErrorLines(Throwable error, List lines) { StackTraceElement[] stack = error.getStackTrace(); List filteredStack = new ArrayList<>(); boolean hasSeenOwnClass = false; diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index c36c59a3e4..3c912b352a 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -426,7 +426,23 @@ else if (moduleInfo) { buffer.append(moduleBuffer); } else { - new LambdaProcessor().processClass(root); + try { + new LambdaProcessor().processClass(root); + } catch (Throwable t) { + DecompilerContext.getLogger().writeMessage("Class " + root.simpleName + " couldn't be written.", + IFernflowerLogger.Severity.WARN, + t); + buffer.append("// $FF: Couldn't be decompiled"); + buffer.appendLineSeparator(); + List lines = new ArrayList<>(); + ClassWriter.collectErrorLines(t, lines); + for (String line : lines) { + buffer.append("//"); + if (!line.isEmpty()) buffer.append(' ').append(line); + buffer.appendLineSeparator(); + } + return; + } // add simple class names to implicit import addClassNameToImport(root, importCollector); @@ -434,11 +450,25 @@ else if (moduleInfo) { // build wrappers for all nested classes (that's where actual processing takes place) initWrappers(root); - // TODO: need to wrap around with try catch as failure here can break the entire class - - new NestedClassProcessor().processClass(root, root); - - new NestedMemberAccess().propagateMemberAccess(root); + try { + new NestedClassProcessor().processClass(root, root); + + new NestedMemberAccess().propagateMemberAccess(root); + } catch (Throwable t) { + DecompilerContext.getLogger().writeMessage("Class " + root.simpleName + " couldn't be written.", + IFernflowerLogger.Severity.WARN, + t); + buffer.append("// $FF: Couldn't be decompiled"); + buffer.appendLineSeparator(); + List lines = new ArrayList<>(); + ClassWriter.collectErrorLines(t, lines); + for (String line : lines) { + buffer.append("//"); + if (!line.isEmpty()) buffer.append(' ').append(line); + buffer.appendLineSeparator(); + } + return; + } TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE); new ClassWriter().classToJava(root, classBuffer, 0); From 7edc6b32785caa34ecc7d1601ea03924e91ffb64 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sat, 27 Nov 2021 18:09:46 -0500 Subject: [PATCH 55/85] Improve readme --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a9f661c72c..6fb8265313 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,18 @@ ### Quiltflower -Quiltflower is a fork of Fernflower and ForgeFlower adding additional features for use with the Quilt toolchain. +Quiltflower is a modern, general purpose decompiler focused on improving code quality, speed, and usability. Quiltflower is a fork of Fernflower and Forgeflower. Changes include: +- New language features (Try with resources, switch expressions, pattern matching, and more) +- Better control flow generation (loops, try-catch, and switch, etc.) +- More configurability +- Better error messages - Javadoc application - Multithreading -- Handful of other fixes +- Optimization +- Many other miscellaneous features and fixes + +For support or questions, please join the [Quilt toolchain discord.](https://discord.quiltmc.org/toolchain) When pulling from upstream, use https://github.com/fesh0r/fernflower @@ -17,6 +24,7 @@ To contribute, please check out [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHIT * Forge Team- For maintaining ForgeFlower * CFR- For it's large suite of very useful tests +Fernflower's readme is preserved below: ### About Fernflower Fernflower is the first actually working analytical decompiler for Java and From 33f00645beb10531b685104e99f38ac12ba0cdd6 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sat, 27 Nov 2021 21:55:33 -0500 Subject: [PATCH 56/85] Fix NPE with initializer processor --- .../jetbrains/java/decompiler/main/InitializerProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java index e151ea32be..a7d07c2130 100644 --- a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java @@ -150,7 +150,7 @@ public static void hideInitalizers(ClassWrapper wrapper) { 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.type == ClassNode.CLASS_ANONYMOUS) || (node.access & CodeConstants.ACC_SYNTHETIC) != 0) { + 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)); } From 1b8ed56b5a285c6364e6354e0dea985db94ee3d1 Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 28 Nov 2021 12:57:34 +0000 Subject: [PATCH 57/85] Some formatting improvements --- .../java/decompiler/main/RecordHelper.java | 9 ++-- .../decompiler/exps/FunctionExprent.java | 4 +- .../decompiler/exps/InvocationExprent.java | 17 +++----- .../modules/decompiler/exps/NewExprent.java | 10 ++++- .../pkg/TestBinaryOperationWrapping.dec | 42 +++++++++---------- testData/results/pkg/TestRecordBig.dec | 3 +- 6 files changed, 44 insertions(+), 41 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/RecordHelper.java b/src/org/jetbrains/java/decompiler/main/RecordHelper.java index d6734b2606..6f426f0449 100644 --- a/src/org/jetbrains/java/decompiler/main/RecordHelper.java +++ b/src/org/jetbrains/java/decompiler/main/RecordHelper.java @@ -28,18 +28,19 @@ public static boolean isHiddenRecordMethod(StructClass cl, StructMethod mt, Root public static void appendRecordComponents(TextBuffer buffer, StructClass cl, List components, int indent) { buffer.pushNewlineGroup(indent, 1); + buffer.appendPossibleNewline(); + buffer.pushNewlineGroup(indent, 0); for (int i = 0; i < components.size(); i++) { StructRecordComponent cd = components.get(i); if (i > 0) { - buffer.append(","); - buffer.appendPossibleNewline(" "); - } else { - buffer.appendPossibleNewline(); + buffer.append(",").appendPossibleNewline(" "); } boolean varArgComponent = i == components.size() - 1 && isVarArgRecord(cl); recordComponentToJava(buffer, cl, cd, i, varArgComponent); } buffer.popNewlineGroup(); + buffer.appendPossibleNewline("", true); + buffer.popNewlineGroup(); } private static Exprent getSimpleReturnValue(RootStatement root) { 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 448d12c421..c3324c6afd 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -541,7 +541,7 @@ public TextBuffer toJava(int indent) { buf.pushNewlineGroup(indent, 1); } buf.append(leftOperand) - .append(" ").append(OPERATORS[funcType]).appendPossibleNewline(" ") + .appendPossibleNewline(" ").append(OPERATORS[funcType]).append(" ") .append(rightOperand); if (!disableNewlineGroupCreation) { buf.popNewlineGroup(); @@ -567,7 +567,7 @@ else if (left.type == EXPRENT_CONST) { buf.pushNewlineGroup(indent, 1); } buf.append(wrapOperandString(lstOperands.get(0), false, indent, true)) - .append(" ").append(OPERATORS[funcType - FUNCTION_EQ + 11]).appendPossibleNewline(" ") + .appendPossibleNewline(" ").append(OPERATORS[funcType - FUNCTION_EQ + 11]).append(" ") .append(wrapOperandString(lstOperands.get(1), true, indent, true)); if (!disableNewlineGroupCreation) { buf.popNewlineGroup(); 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 82fe2c824a..61112a07ac 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -900,7 +900,9 @@ else if (inv.isUnboxingCall() && !inv.shouldForceUnboxing()) { boolean firstParameter = true; - boolean pushedNestedGroup = false; + buf.appendPossibleNewline(); + buf.pushNewlineGroup(indent, 0); + for (int i = start; i < lstParameters.size(); i++) { if (mask == null || mask.get(i) == null) { TextBuffer buff = new TextBuffer(); @@ -944,12 +946,7 @@ else if (desc != null && desc.getSignature() != null && genericArgs.size() != 0) // the last "new Object[0]" in the vararg call is not printed if (buff.length() > 0) { if (!firstParameter) { - buf.append(","); - buf.appendPossibleNewline(" "); - } else { - buf.appendPossibleNewline(); - buf.pushNewlineGroup(indent, 0); - pushedNestedGroup = true; + buf.append(",").appendPossibleNewline(" "); } buf.append(buff); } @@ -957,13 +954,11 @@ else if (desc != null && desc.getSignature() != null && genericArgs.size() != 0) firstParameter = false; } } - if (pushedNestedGroup) { - buf.popNewlineGroup(); - } + buf.popNewlineGroup(); buf.appendPossibleNewline("", true); - buf.popNewlineGroup(); + return buf; } 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 8c484a4782..1ef9e29ca8 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -455,7 +455,7 @@ else if (isVarArgParam) { VarType leftType = newType.decreaseArrayDim(); for (int i = 0; i < lstArrayElements.size(); i++) { if (i > 0) { - buf.append(", "); + buf.append(",").appendPossibleNewline(" "); } // new String[][]{{"abc"}, {"DEF"}} => new String[]{"abc"}, new String[]{"DEF"} @@ -493,13 +493,19 @@ else if (isVarArgParam) { VarType leftType = newType.decreaseArrayDim(); buf.append('{'); + buf.pushNewlineGroup(indent, 1); + buf.appendPossibleNewline(); + buf.pushNewlineGroup(indent, 0); for (int i = 0; i < lstArrayElements.size(); i++) { if (i > 0) { - buf.append(", "); + buf.append(",").appendPossibleNewline(" "); } ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false); } + buf.popNewlineGroup(); + buf.appendPossibleNewline("", true); buf.append('}'); + buf.popNewlineGroup(); } } diff --git a/testData/results/pkg/TestBinaryOperationWrapping.dec b/testData/results/pkg/TestBinaryOperationWrapping.dec index 1c0cfa8f2a..22c6bad0f7 100644 --- a/testData/results/pkg/TestBinaryOperationWrapping.dec +++ b/testData/results/pkg/TestBinaryOperationWrapping.dec @@ -4,12 +4,12 @@ public class TestBinaryOperationWrapping { public void testStringConcatenation(String longVariableName) { System.out// 5 .println( - "This is a very very very very very very very very very very very very very very very long string" + - longVariableName + - longVariableName + - longVariableName + - longVariableName + - longVariableName + "This is a very very very very very very very very very very very very very very very long string" + + longVariableName + + longVariableName + + longVariableName + + longVariableName + + longVariableName ); }// 9 @@ -47,21 +47,21 @@ public class TestBinaryOperationWrapping { ) { System.out// 12 .println( - a && b || - c && d || - e && f || - g && h || - i && j || - k && l || - m && n || - o && p || - q && r || - s && t || - u && v || - w && x || - y && z || - a1 && b1 || - c1 && d1 + a && b + || c && d + || e && f + || g && h + || i && j + || k && l + || m && n + || o && p + || q && r + || s && t + || u && v + || w && x + || y && z + || a1 && b1 + || c1 && d1 ); }// 13 } diff --git a/testData/results/pkg/TestRecordBig.dec b/testData/results/pkg/TestRecordBig.dec index fb93212751..81cc29df75 100644 --- a/testData/results/pkg/TestRecordBig.dec +++ b/testData/results/pkg/TestRecordBig.dec @@ -16,6 +16,7 @@ public record TestRecordBig( int comp13, int comp14, int comp15, - int comp16) { + int comp16 +) { } From 632825360e2df3b464807c78e27ca586b5d76cba Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sun, 28 Nov 2021 08:57:55 -0500 Subject: [PATCH 58/85] Add more tests, tiny changes --- .../modules/decompiler/DecHelper.java | 2 + .../java/decompiler/util/DotExporter.java | 2 +- .../java/decompiler/util/TextBuffer.java | 2 +- .../java/decompiler/SingleClassesTest.java | 3 + testData/results/TestEclipseSwitchString.dec | 403 ++++++++++++++++++ .../results/pkg/TestNestedAnonymousClass.dec | 73 ++++ testData/results/pkg/TestPPMMLoop.dec | 117 +++++ .../java8/pkg/TestNestedAnonymousClass.java | 29 ++ testData/src/java8/pkg/TestPPMMLoop.java | 27 ++ 9 files changed, 656 insertions(+), 2 deletions(-) create mode 100644 testData/results/TestEclipseSwitchString.dec create mode 100644 testData/results/pkg/TestNestedAnonymousClass.dec create mode 100644 testData/results/pkg/TestPPMMLoop.dec create mode 100644 testData/src/java8/pkg/TestNestedAnonymousClass.java create mode 100644 testData/src/java8/pkg/TestPPMMLoop.java diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java index 50613fcb97..0911be421d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java @@ -183,6 +183,8 @@ else if (lstEdges.size() == 1) { return true; } + // Finds all catch blocks that this statement can flow to, and retain those that only have a single exception predecessor + // aka they have a single statement in their try block (presumably a sequence) public static Set getUniquePredExceptions(Statement head) { Set setHandlers = new HashSet<>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD)); setHandlers.removeIf(statement -> statement.getPredecessorEdges(StatEdge.TYPE_EXCEPTION).size() > 1); diff --git a/src/org/jetbrains/java/decompiler/util/DotExporter.java b/src/org/jetbrains/java/decompiler/util/DotExporter.java index 2ced487722..98474facb2 100644 --- a/src/org/jetbrains/java/decompiler/util/DotExporter.java +++ b/src/org/jetbrains/java/decompiler/util/DotExporter.java @@ -68,7 +68,7 @@ private static String statToDot(Statement stat, String name) { } if (ifs.getElseEdge() != null) { - extraData.put(ifs.getElseEdge(), "If Edge"); + extraData.put(ifs.getElseEdge(), "Else Edge"); } } } diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index deccdee442..c9865533a6 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -119,7 +119,7 @@ public TextBuffer appendPossibleNewline(String alternative, boolean dedent) { public TextBuffer popNewlineGroup() { if (myCurrentGroup == myRootGroup) { - throw new IllegalStateException("Cannot pop root group"); + throw new IllegalStateException("Cannot pop root group: " + this.convertToStringAndAllowDataDiscard()); } assert myStringBuilder.length() >= myCurrentGroup.myStart; myCurrentGroup.myLength = myStringBuilder.length() - myCurrentGroup.myStart; diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 2d5a4407f2..4d3d8c201d 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -440,6 +440,9 @@ private void registerDefault() { register(JAVA_8, "TestFinallyThrow"); register(JAVA_8, "TestWhile1"); registerRaw(CUSTOM, "TestEclipseSwitchEnum"); + registerRaw(CUSTOM, "TestEclipseSwitchString"); + register(JAVA_8, "TestNestedAnonymousClass"); + register(JAVA_8, "TestPPMMLoop"); } private void registerEntireClassPath() { diff --git a/testData/results/TestEclipseSwitchString.dec b/testData/results/TestEclipseSwitchString.dec new file mode 100644 index 0000000000..55978d32a8 --- /dev/null +++ b/testData/results/TestEclipseSwitchString.dec @@ -0,0 +1,403 @@ +package pkg; + +public class TestEclipseSwitchString { + public int test(String var1) { + switch(var1.hashCode()) {// 5 + case 49: + if (var1.equals("1")) { + return 1;// 10 + } + break; + case 50: + if (var1.equals("2")) { + return 2;// 12 + } + } + + System.out.println("Test");// 7 + return 0;// 8 15 + } + + public int test1(String var1) { + label20: { + switch(var1.hashCode()) {// 19 + case 49: + if (var1.equals("1")) { + return 1;// 24 + } + break label20; + case 50: + if (!var1.equals("2")) { + break label20; + } + break; + case 51: + if (!var1.equals("3")) { + break label20; + } + break; + default: + break label20; + } + + return 2;// 27 + } + + System.out.println("Test");// 21 + return 0;// 22 30 + } + + public int test2(String var1) { + label21: { + switch(var1.hashCode()) {// 34 + case 49: + if (!var1.equals("1")) { + break label21; + } + + System.out.println("Hello");// 39 + break; + case 50: + if (!var1.equals("2")) { + break label21; + } + break; + case 51: + if (!var1.equals("3")) { + break label21; + } + break; + default: + break label21; + } + + return 2;// 42 + } + + System.out.println("Test");// 36 + return 0;// 37 45 + } + + public int testHashcodeCollision(String var1) { + switch(var1.hashCode()) {// 49 + case 2112: + if (var1.equals("BB")) { + return 1;// 54 + } else if (var1.equals("Aa")) { + return 2;// 56 + } + default: + System.out.println("Test");// 51 + return 0;// 52 58 + } + } + + public int testHashcodeCollision1(String var1) { + switch(var1.hashCode()) {// 62 + case 2112: + if (var1.equals("BB") || var1.equals("Aa")) { + return 2;// 68 + } + } + + System.out.println("Test");// 64 + return 0;// 65 70 + } + + public int testHashcodeCollision2(String var1) { + switch(var1.hashCode()) {// 74 + case 2112: + label13: { + if (!var1.equals("BB")) { + if (!var1.equals("Aa")) { + break label13; + } + } else { + System.out.println("BB");// 79 + } + + return 2;// 81 + } + } + + System.out.println("Test");// 76 + return 0;// 77 83 + } +} + +class 'pkg/TestEclipseSwitchString' { + method 'test (Ljava/lang/String;)I' { + 0 4 + 3 4 + 4 4 + 5 4 + 6 4 + 21 6 + 22 6 + 23 6 + 24 6 + 25 6 + 26 6 + 2d 11 + 2e 11 + 2f 11 + 30 11 + 31 11 + 32 11 + 35 16 + 36 16 + 37 16 + 38 16 + 39 16 + 3a 16 + 3b 16 + 3c 16 + 3d 17 + 3e 17 + 3f 17 + 40 7 + 41 7 + 42 12 + 43 12 + 44 17 + } + + method 'test1 (Ljava/lang/String;)I' { + 0 22 + 3 22 + 4 22 + 5 22 + 6 22 + 29 24 + 2a 24 + 2b 24 + 2c 24 + 2d 24 + 2e 24 + 35 29 + 36 29 + 37 29 + 38 29 + 39 29 + 3a 29 + 41 34 + 42 34 + 43 34 + 44 34 + 45 34 + 46 34 + 49 45 + 4a 45 + 4b 45 + 4c 45 + 4d 45 + 4e 45 + 4f 45 + 50 45 + 51 46 + 52 46 + 53 46 + 54 25 + 55 25 + 56 42 + 57 42 + 58 46 + } + + method 'test2 (Ljava/lang/String;)I' { + 0 51 + 3 51 + 4 51 + 5 51 + 6 51 + 29 53 + 2a 53 + 2b 53 + 2c 53 + 2d 53 + 2e 53 + 35 60 + 36 60 + 37 60 + 38 60 + 39 60 + 3a 60 + 41 65 + 42 65 + 43 65 + 44 65 + 45 65 + 46 65 + 49 76 + 4a 76 + 4b 76 + 4c 76 + 4d 76 + 4e 76 + 4f 76 + 50 76 + 51 77 + 52 77 + 53 77 + 54 57 + 55 57 + 56 57 + 57 57 + 58 57 + 59 57 + 5a 77 + 5b 77 + 5c 73 + 5d 73 + 5e 77 + } + + method 'testHashcodeCollision (Ljava/lang/String;)I' { + 0 81 + 3 81 + 4 81 + 5 81 + 6 81 + 19 83 + 1a 83 + 1b 83 + 1c 83 + 1d 83 + 1e 83 + 22 85 + 23 85 + 24 85 + 25 85 + 26 85 + 27 85 + 2a 89 + 2b 89 + 2c 89 + 2d 89 + 2e 89 + 2f 89 + 30 89 + 31 89 + 32 90 + 33 90 + 34 90 + 35 84 + 36 84 + 37 86 + 38 86 + 39 90 + } + + method 'testHashcodeCollision1 (Ljava/lang/String;)I' { + 0 95 + 3 95 + 4 95 + 5 95 + 6 95 + 19 97 + 1a 97 + 1b 97 + 1c 97 + 1d 97 + 1e 97 + 22 97 + 23 97 + 24 97 + 25 97 + 26 97 + 27 97 + 2a 102 + 2b 102 + 2c 102 + 2d 102 + 2e 102 + 2f 102 + 30 102 + 31 102 + 32 103 + 33 103 + 34 103 + 35 98 + 36 98 + 37 103 + } + + method 'testHashcodeCollision2 (Ljava/lang/String;)I' { + 0 107 + 3 107 + 4 107 + 5 107 + 6 107 + 19 110 + 1a 110 + 1b 110 + 1c 110 + 1d 110 + 1e 110 + 22 111 + 23 111 + 24 111 + 25 111 + 26 111 + 27 111 + 2a 122 + 2b 122 + 2c 122 + 2d 122 + 2e 122 + 2f 122 + 30 122 + 31 122 + 32 123 + 33 123 + 34 123 + 35 115 + 36 115 + 37 115 + 38 115 + 39 115 + 3a 115 + 3b 123 + 3c 123 + 3d 118 + 3e 118 + 3f 123 + } +} + +Lines mapping: +5 <-> 5 +7 <-> 17 +8 <-> 18 +10 <-> 8 +12 <-> 13 +15 <-> 18 +19 <-> 23 +21 <-> 46 +22 <-> 47 +24 <-> 26 +27 <-> 43 +30 <-> 47 +34 <-> 52 +36 <-> 77 +37 <-> 78 +39 <-> 58 +42 <-> 74 +45 <-> 78 +49 <-> 82 +51 <-> 90 +52 <-> 91 +54 <-> 85 +56 <-> 87 +58 <-> 91 +62 <-> 96 +64 <-> 103 +65 <-> 104 +68 <-> 99 +70 <-> 104 +74 <-> 108 +76 <-> 123 +77 <-> 124 +79 <-> 116 +81 <-> 119 +83 <-> 124 diff --git a/testData/results/pkg/TestNestedAnonymousClass.dec b/testData/results/pkg/TestNestedAnonymousClass.dec new file mode 100644 index 0000000000..9737558ca9 --- /dev/null +++ b/testData/results/pkg/TestNestedAnonymousClass.dec @@ -0,0 +1,73 @@ +package pkg; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class TestNestedAnonymousClass { + public Runnable r = new TestNestedAnonymousClass.B() { + public void run() { + ExecutorService ex = Executors.newFixedThreadPool(1);// 9 + ex.submit(new Runnable() {// 10 + public void run() { + // $FF: Couldn't be decompiled + // Bytecode: + // 00: getstatic java/lang/System.out Ljava/io/PrintStream; + // 03: ldc "Hello" + // 05: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 08: aload 0 + // 09: getfield pkg/TestNestedAnonymousClass$1$1.this$1 Lpkg/TestNestedAnonymousClass$1; + // 0c: invokevirtual pkg/TestNestedAnonymousClass$1.b ()V + // 0f: aload 0 + // 10: getfield pkg/TestNestedAnonymousClass$1$1.this$1 Lpkg/TestNestedAnonymousClass$1; + // 13: getfield pkg/TestNestedAnonymousClass$1.this$0 Lpkg/TestNestedAnonymousClass; + // 16: invokevirtual pkg/TestNestedAnonymousClass.a ()V + // 19: return + } + }); + }// 17 + }; + + public void a() { + }// 28 + + public abstract class B implements Runnable { + protected void b() { + }// 23 + } +} + +class 'pkg/TestNestedAnonymousClass$1' { + method 'run ()V' { + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 9 + e 9 + f 9 + 10 9 + 11 9 + 12 9 + 14 26 + } +} + +class 'pkg/TestNestedAnonymousClass' { + method 'a ()V' { + 0 30 + } +} + +class 'pkg/TestNestedAnonymousClass$B' { + method 'b ()V' { + 0 34 + } +} + +Lines mapping: +9 <-> 9 +10 <-> 10 +17 <-> 27 +23 <-> 35 +28 <-> 31 diff --git a/testData/results/pkg/TestPPMMLoop.dec b/testData/results/pkg/TestPPMMLoop.dec new file mode 100644 index 0000000000..e3e0a2c75f --- /dev/null +++ b/testData/results/pkg/TestPPMMLoop.dec @@ -0,0 +1,117 @@ +package pkg; + +public class TestPPMMLoop { + public void test(int a, String s) { + while(true) { + ++a;// 5 + if (a <= 0) { + return;// 8 + } + + s = s + "a";// 6 + } + } + + public void test1(int a, String s) { + while(a++ > 0) {// 11 + s = s + "a";// 12 + } + + }// 14 + + public void test2(int a, String s) { + while(true) { + --a;// 17 + if (a <= 0) { + return;// 20 + } + + s = s + "a";// 18 + } + } + + public void test3(int a, String s) { + while(a-- > 0) {// 23 + s = s + "a";// 24 + } + + }// 26 +} + +class 'pkg/TestPPMMLoop' { + method 'test (ILjava/lang/String;)V' { + 0 5 + 1 5 + 2 5 + 3 6 + 4 6 + e 10 + 12 10 + 13 10 + 17 10 + 18 10 + 19 10 + 1a 10 + 1e 7 + } + + method 'test1 (ILjava/lang/String;)V' { + 1 15 + 2 15 + 3 15 + 4 15 + e 16 + 12 16 + 13 16 + 17 16 + 18 16 + 19 16 + 1a 16 + 1e 19 + } + + method 'test2 (ILjava/lang/String;)V' { + 0 23 + 1 23 + 2 23 + 3 24 + 4 24 + e 28 + 12 28 + 13 28 + 17 28 + 18 28 + 19 28 + 1a 28 + 1e 25 + } + + method 'test3 (ILjava/lang/String;)V' { + 1 33 + 2 33 + 3 33 + 4 33 + e 34 + 12 34 + 13 34 + 17 34 + 18 34 + 19 34 + 1a 34 + 1e 37 + } +} + +Lines mapping: +5 <-> 6 +6 <-> 11 +8 <-> 8 +11 <-> 16 +12 <-> 17 +14 <-> 20 +17 <-> 24 +18 <-> 29 +20 <-> 26 +23 <-> 34 +24 <-> 35 +26 <-> 38 diff --git a/testData/src/java8/pkg/TestNestedAnonymousClass.java b/testData/src/java8/pkg/TestNestedAnonymousClass.java new file mode 100644 index 0000000000..1c0558ef84 --- /dev/null +++ b/testData/src/java8/pkg/TestNestedAnonymousClass.java @@ -0,0 +1,29 @@ +package pkg; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class TestNestedAnonymousClass { + public Runnable r = new B() { + public void run() { + ExecutorService ex = Executors.newFixedThreadPool(1); + ex.submit(new Runnable() { + public void run() { + System.out.println("Hello"); + b(); + TestNestedAnonymousClass.this.a(); + } + }); + } + }; + + public abstract class B implements Runnable { + protected void b() { + + } + } + + public void a() { + + } +} diff --git a/testData/src/java8/pkg/TestPPMMLoop.java b/testData/src/java8/pkg/TestPPMMLoop.java new file mode 100644 index 0000000000..dcc0316145 --- /dev/null +++ b/testData/src/java8/pkg/TestPPMMLoop.java @@ -0,0 +1,27 @@ +package pkg; + +public class TestPPMMLoop { + public void test(int a, String s) { + while (++a > 0) { + s += "a"; + } + } + + public void test1(int a, String s) { + while (a++ > 0) { + s += "a"; + } + } + + public void test2(int a, String s) { + while (--a > 0) { + s += "a"; + } + } + + public void test3(int a, String s) { + while (a-- > 0) { + s += "a"; + } + } +} From d4da1857095eba44d54294b2f8c6a6b0f5ca0ed4 Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 28 Nov 2021 17:00:03 +0000 Subject: [PATCH 59/85] Fix IllegalStateException --- .../decompiler/exps/InvocationExprent.java | 2 +- .../results/pkg/TestNestedAnonymousClass.dec | 60 ++++++++++++------- 2 files changed, 41 insertions(+), 21 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 61112a07ac..d70e2c846f 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -688,7 +688,7 @@ else if (JAVA_NIO_BUFFER.equals(descriptor.ret) && !JAVA_NIO_BUFFER.equals(right switch (functype) { case TYP_GENERAL: if (buf.contentEquals(VarExprent.VAR_NAMELESS_ENCLOSURE)) { - buf = new TextBuffer(); + buf.setLength(0); } if (buf.length() > 0) { diff --git a/testData/results/pkg/TestNestedAnonymousClass.dec b/testData/results/pkg/TestNestedAnonymousClass.dec index 9737558ca9..80693d49bd 100644 --- a/testData/results/pkg/TestNestedAnonymousClass.dec +++ b/testData/results/pkg/TestNestedAnonymousClass.dec @@ -9,20 +9,10 @@ public class TestNestedAnonymousClass { ExecutorService ex = Executors.newFixedThreadPool(1);// 9 ex.submit(new Runnable() {// 10 public void run() { - // $FF: Couldn't be decompiled - // Bytecode: - // 00: getstatic java/lang/System.out Ljava/io/PrintStream; - // 03: ldc "Hello" - // 05: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 08: aload 0 - // 09: getfield pkg/TestNestedAnonymousClass$1$1.this$1 Lpkg/TestNestedAnonymousClass$1; - // 0c: invokevirtual pkg/TestNestedAnonymousClass$1.b ()V - // 0f: aload 0 - // 10: getfield pkg/TestNestedAnonymousClass$1$1.this$1 Lpkg/TestNestedAnonymousClass$1; - // 13: getfield pkg/TestNestedAnonymousClass$1.this$0 Lpkg/TestNestedAnonymousClass; - // 16: invokevirtual pkg/TestNestedAnonymousClass.a ()V - // 19: return - } + System.out.println("Hello");// 12 + b();// 13 + TestNestedAnonymousClass.this.a();// 14 + }// 15 }); }// 17 }; @@ -49,25 +39,55 @@ class 'pkg/TestNestedAnonymousClass$1' { 10 9 11 9 12 9 - 14 26 + 14 16 + } +} + +class 'pkg/TestNestedAnonymousClass$1$1' { + method 'run ()V' { + 0 11 + 1 11 + 2 11 + 3 11 + 4 11 + 5 11 + 6 11 + 7 11 + 9 12 + a 12 + b 12 + c 12 + d 12 + e 12 + 13 13 + 14 13 + 15 13 + 16 13 + 17 13 + 18 13 + 19 14 } } class 'pkg/TestNestedAnonymousClass' { method 'a ()V' { - 0 30 + 0 20 } } class 'pkg/TestNestedAnonymousClass$B' { method 'b ()V' { - 0 34 + 0 24 } } Lines mapping: 9 <-> 9 10 <-> 10 -17 <-> 27 -23 <-> 35 -28 <-> 31 +12 <-> 12 +13 <-> 13 +14 <-> 14 +15 <-> 15 +17 <-> 17 +23 <-> 25 +28 <-> 21 From 4a9d21d73a9c2bd9502a2a9e26423704dda8c60e Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Sun, 28 Nov 2021 20:09:48 -0500 Subject: [PATCH 60/85] Add new tests --- .../modules/decompiler/LoopExtractHelper.java | 1 - .../java/decompiler/util/DotExporter.java | 1 - .../java/decompiler/SingleClassesTest.java | 11 + testData/results/pkg/TestArrayAssign.dec | 91 ++++++++ testData/results/pkg/TestDoWhileMerge.dec | 156 ++++++++++++++ .../results/pkg/TestForeachMultipleLoops.dec | 203 ++++++++++++++++++ testData/results/pkg/TestLoopBreak3.dec | 100 +++++++++ testData/results/pkg/TestTernaryReturn.dec | 95 ++++++++ testData/src/java8/pkg/TestArrayAssign.java | 23 ++ testData/src/java8/pkg/TestDoWhileMerge.java | 38 ++++ .../java8/pkg/TestForeachMultipleLoops.java | 41 ++++ testData/src/java8/pkg/TestLoopBreak3.java | 25 +++ testData/src/java8/pkg/TestTernaryReturn.java | 16 ++ 13 files changed, 799 insertions(+), 2 deletions(-) create mode 100644 testData/results/pkg/TestArrayAssign.dec create mode 100644 testData/results/pkg/TestDoWhileMerge.dec create mode 100644 testData/results/pkg/TestForeachMultipleLoops.dec create mode 100644 testData/results/pkg/TestLoopBreak3.dec create mode 100644 testData/results/pkg/TestTernaryReturn.dec create mode 100644 testData/src/java8/pkg/TestArrayAssign.java create mode 100644 testData/src/java8/pkg/TestDoWhileMerge.java create mode 100644 testData/src/java8/pkg/TestForeachMultipleLoops.java create mode 100644 testData/src/java8/pkg/TestLoopBreak3.java create mode 100644 testData/src/java8/pkg/TestTernaryReturn.java diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java index 84fa12723a..9d53a5367e 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java @@ -23,7 +23,6 @@ public static boolean extractLoops(Statement root) { if (res) { SequenceHelper.condenseSequences(root); - } return res; diff --git a/src/org/jetbrains/java/decompiler/util/DotExporter.java b/src/org/jetbrains/java/decompiler/util/DotExporter.java index 98474facb2..97b4932893 100644 --- a/src/org/jetbrains/java/decompiler/util/DotExporter.java +++ b/src/org/jetbrains/java/decompiler/util/DotExporter.java @@ -97,7 +97,6 @@ private static String statToDot(Statement stat, String name) { buffer.append(sourceId + "->" + clsId + " [arrowhead=diamond,label=\"Closure\"];\r\n"); } - // TODO: why are some returns break edges instead of returns? if (edge.getType() == StatEdge.TYPE_FINALLYEXIT || edge.getType() == StatEdge.TYPE_BREAK) { exits.add(edge.getDestination().id); } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 4d3d8c201d..290e1cf84a 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -442,7 +442,18 @@ private void registerDefault() { registerRaw(CUSTOM, "TestEclipseSwitchEnum"); registerRaw(CUSTOM, "TestEclipseSwitchString"); register(JAVA_8, "TestNestedAnonymousClass"); + // TODO: pre increment not inlined properly register(JAVA_8, "TestPPMMLoop"); + // TODO: loops not eliminated properly, foreach not created + register(JAVA_8, "TestForeachMultipleLoops"); + // TODO: break turned into labeled continue + register(JAVA_8, "TestLoopBreak3"); + // TODO: do-while loop entirely eliminated in test(), not created in test1() + register(JAVA_8, "TestDoWhileMerge"); + // TODO: ternary not correct, also needs Java 1.0 test- looks different + register(JAVA_8, "TestTernaryReturn"); + // TODO: method access causes improper stack var simplification + register(JAVA_8, "TestArrayAssign"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestArrayAssign.dec b/testData/results/pkg/TestArrayAssign.dec new file mode 100644 index 0000000000..5f66d9266b --- /dev/null +++ b/testData/results/pkg/TestArrayAssign.dec @@ -0,0 +1,91 @@ +package pkg; + +public class TestArrayAssign { + public void test(TestArrayAssign.Holder holder, int i, double inc) { + for(int j = 0; j < i; ++j) {// 5 + double[] var10000 = holder.get();// 6 + var10000[j] += inc; + } + + }// 8 + + public void test1(TestArrayAssign.Holder holder, int i, double inc) { + for(int j = 0; j < i; ++j) {// 11 + holder.a[j] += inc;// 12 + } + + }// 14 + + public class Holder { + public double[] a; + + public double[] get() { + return this.a;// 20 + } + } +} + +class 'pkg/TestArrayAssign' { + method 'test (Lpkg/TestArrayAssign$Holder;ID)V' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 6 4 + 9 5 + a 5 + b 5 + c 5 + d 6 + e 6 + 11 6 + 13 6 + 14 4 + 15 4 + 16 4 + 1a 9 + } + + method 'test1 (Lpkg/TestArrayAssign$Holder;ID)V' { + 0 12 + 1 12 + 2 12 + 3 12 + 4 12 + 5 12 + 6 12 + 9 13 + a 13 + b 13 + c 13 + d 13 + e 13 + 11 13 + 13 13 + 14 12 + 15 12 + 16 12 + 1a 16 + } +} + +class 'pkg/TestArrayAssign$Holder' { + method 'get ()[D' { + 0 22 + 1 22 + 2 22 + 3 22 + 4 22 + } +} + +Lines mapping: +5 <-> 5 +6 <-> 6 +8 <-> 10 +11 <-> 13 +12 <-> 14 +14 <-> 17 +20 <-> 23 diff --git a/testData/results/pkg/TestDoWhileMerge.dec b/testData/results/pkg/TestDoWhileMerge.dec new file mode 100644 index 0000000000..8e928c8c45 --- /dev/null +++ b/testData/results/pkg/TestDoWhileMerge.dec @@ -0,0 +1,156 @@ +package pkg; + +public class TestDoWhileMerge { + public void test(boolean b, int j) { + for(int i = 0; i < j; ++i) {// 6 + System.out.println(i);// 8 + ++i;// 9 + if (i == 30) {// 11 + return;// 12 + } + + if (!b || i >= 40) {// 14 + System.out.println("test");// 16 + } + } + + System.out.println("after");// 19 + }// 20 + + public void test1(boolean b, int j) { + for(int i = 0; i < j; ++i) {// 23 + System.out.println(1);// 24 + + while(true) { + System.out.println(i);// 27 + ++i;// 28 + if (i == 30) {// 30 + return;// 31 + } + + if (!b || i >= 40) {// 33 + break; + } + } + } + + System.out.println("after");// 36 + }// 37 +} + +class 'pkg/TestDoWhileMerge' { + method 'test (ZI)V' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 7 5 + 8 5 + 9 5 + a 5 + b 5 + c 5 + d 5 + e 6 + f 6 + 10 6 + 11 7 + 12 7 + 13 7 + 14 7 + 17 8 + 18 11 + 19 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 4 + 2b 4 + 2c 4 + 30 16 + 31 16 + 32 16 + 33 16 + 34 16 + 35 16 + 36 16 + 37 16 + 38 17 + } + + method 'test1 (ZI)V' { + 0 20 + 1 20 + 2 20 + 3 20 + 4 20 + 7 21 + 8 21 + 9 21 + a 21 + b 21 + e 24 + f 24 + 10 24 + 11 24 + 12 24 + 13 24 + 14 24 + 15 25 + 16 25 + 17 25 + 18 26 + 19 26 + 1a 26 + 1b 26 + 1e 27 + 1f 30 + 20 30 + 23 30 + 24 30 + 25 30 + 26 30 + 29 20 + 2a 20 + 2b 20 + 2f 36 + 30 36 + 31 36 + 32 36 + 33 36 + 34 36 + 35 36 + 36 36 + 37 37 + } +} + +Lines mapping: +6 <-> 5 +8 <-> 6 +9 <-> 7 +11 <-> 8 +12 <-> 9 +14 <-> 12 +16 <-> 13 +19 <-> 17 +20 <-> 18 +23 <-> 21 +24 <-> 22 +27 <-> 25 +28 <-> 26 +30 <-> 27 +31 <-> 28 +33 <-> 31 +36 <-> 37 +37 <-> 38 diff --git a/testData/results/pkg/TestForeachMultipleLoops.dec b/testData/results/pkg/TestForeachMultipleLoops.dec new file mode 100644 index 0000000000..e4a1160fb2 --- /dev/null +++ b/testData/results/pkg/TestForeachMultipleLoops.dec @@ -0,0 +1,203 @@ +package pkg; + +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +public class TestForeachMultipleLoops { + public void test(Object a, Map map, int i) { + if (a != null) {// 8 + System.out.println(a);// 9 + } else { + Iterator var4 = map.entrySet().iterator();// 13 + + while(true) { + while(true) { + Entry entry; + while(true) { + if (!var4.hasNext()) { + return;// 40 + } + + entry = (Entry)var4.next(); + String s = (String)entry.getValue();// 14 + if (a == null) {// 15 + (new StringBuilder()).append(s).append(s).toString();// 16 + break; + } + + if (s == null) {// 18 + s = "hello";// 21 + break; + } + } + + Object v = entry.getValue();// 24 + if (v == null) {// 25 + if (i == 3) {// 26 + continue; + } + + System.out.println("if");// 29 + break; + } + + System.out.println("else");// 31 + break; + } + + try { + System.out.println(1);// 35 + } catch (Exception var9) {// 36 + var9.printStackTrace();// 37 + } + } + } + }// 10 +} + +class 'pkg/TestForeachMultipleLoops' { + method 'test (Ljava/lang/Object;Ljava/util/Map;I)V' { + 0 8 + 1 8 + 4 9 + 5 9 + 6 9 + 7 9 + 8 9 + 9 9 + a 9 + b 55 + c 11 + d 11 + e 11 + f 11 + 10 11 + 11 11 + 12 11 + 13 11 + 14 11 + 15 11 + 16 11 + 17 11 + 18 11 + 19 17 + 1a 17 + 1b 17 + 1c 17 + 1d 17 + 1e 17 + 1f 17 + 20 17 + 23 21 + 24 21 + 25 21 + 26 21 + 27 21 + 28 21 + 29 21 + 2a 21 + 2b 21 + 2c 21 + 2d 21 + 2e 21 + 2f 22 + 30 22 + 31 22 + 32 22 + 33 22 + 34 22 + 35 22 + 36 22 + 37 22 + 38 22 + 39 22 + 3a 22 + 3b 23 + 3c 23 + 46 24 + 47 24 + 48 24 + 49 24 + 4a 24 + 4b 24 + 4c 24 + 4d 24 + 4e 24 + 4f 24 + 50 24 + 51 24 + 52 24 + 55 25 + 58 28 + 59 28 + 5a 28 + 60 29 + 61 29 + 62 29 + 63 29 + 64 34 + 65 34 + 66 34 + 67 34 + 68 34 + 69 34 + 6a 34 + 6b 34 + 6c 34 + 6d 35 + 6e 35 + 6f 35 + 72 36 + 73 36 + 74 36 + 7a 40 + 7b 40 + 7c 40 + 7d 40 + 7e 40 + 7f 40 + 80 40 + 81 40 + 82 41 + 85 44 + 86 44 + 87 44 + 88 44 + 89 44 + 8a 44 + 8d 49 + 8e 49 + 8f 49 + 90 49 + 91 49 + 97 50 + 9b 51 + a1 18 + } +} + +Lines mapping: +8 <-> 9 +9 <-> 10 +10 <-> 56 +13 <-> 12 +14 <-> 23 +15 <-> 24 +16 <-> 25 +18 <-> 29 +21 <-> 30 +24 <-> 35 +25 <-> 36 +26 <-> 37 +29 <-> 41 +31 <-> 45 +35 <-> 50 +36 <-> 51 +37 <-> 52 +40 <-> 19 +Not mapped: +19 +27 +38 +39 diff --git a/testData/results/pkg/TestLoopBreak3.dec b/testData/results/pkg/TestLoopBreak3.dec new file mode 100644 index 0000000000..a9324cea42 --- /dev/null +++ b/testData/results/pkg/TestLoopBreak3.dec @@ -0,0 +1,100 @@ +package pkg; + +public class TestLoopBreak3 { + public void test(int i, boolean b) { + label33: + for(int j = 0; j < i; ++j) {// 5 + System.out.println(j);// 6 + + for(int k = 0; k < j; ++k) {// 8 + if (k == 2) {// 9 + for(int l = 0; l < 2; ++l) {// 10 + System.out.println(2);// 11 + if (!b) {// 13 + continue label33; + } + + System.out.println(l);// 14 + } + break; + } + } + } + + }// 24 +} + +class 'pkg/TestLoopBreak3' { + method 'test (IZ)V' { + 0 5 + 1 5 + 2 5 + 3 5 + 4 5 + 7 6 + 8 6 + 9 6 + a 6 + b 6 + c 6 + d 6 + e 8 + f 8 + 10 8 + 11 8 + 12 8 + 13 8 + 14 8 + 17 9 + 18 9 + 19 9 + 1a 9 + 1d 10 + 1e 10 + 1f 10 + 20 10 + 21 10 + 22 10 + 23 10 + 26 11 + 27 11 + 28 11 + 29 11 + 2a 11 + 2b 11 + 2c 11 + 2d 12 + 2e 12 + 31 16 + 32 16 + 33 16 + 34 16 + 35 16 + 36 16 + 37 16 + 38 16 + 39 10 + 3a 10 + 3b 10 + 42 8 + 43 8 + 44 8 + 48 5 + 49 5 + 4a 5 + 4e 23 + } +} + +Lines mapping: +5 <-> 6 +6 <-> 7 +8 <-> 9 +9 <-> 10 +10 <-> 11 +11 <-> 12 +13 <-> 13 +14 <-> 17 +24 <-> 24 +Not mapped: +20 diff --git a/testData/results/pkg/TestTernaryReturn.dec b/testData/results/pkg/TestTernaryReturn.dec new file mode 100644 index 0000000000..ad26c28937 --- /dev/null +++ b/testData/results/pkg/TestTernaryReturn.dec @@ -0,0 +1,95 @@ +package pkg; + +public class TestTernaryReturn { + public Object a; + public Object b; + + public boolean test(Object o) { + if (!(o instanceof TestTernaryReturn)) {// 8 + return false;// 9 + } else { + TestTernaryReturn p = (TestTernaryReturn)o;// 12 + label26: + if (this.a == null ? p.a == null : this.a.equals(p.a)) {// 14 + if (this.b == null) { + if (p.b == null) { + return true; + } + } else if (this.b.equals(p.b)) { + return true; + } + } + + return false; + } + } +} + +class 'pkg/TestTernaryReturn' { + method 'test (Ljava/lang/Object;)Z' { + 0 7 + 1 7 + 2 7 + 3 7 + 4 7 + 7 8 + 8 8 + 9 10 + a 10 + b 10 + c 10 + d 10 + e 12 + f 12 + 10 12 + 11 12 + 12 12 + 15 12 + 16 12 + 17 12 + 18 12 + 19 12 + 1f 12 + 20 12 + 21 12 + 22 12 + 23 12 + 24 12 + 25 12 + 26 12 + 27 12 + 28 12 + 29 12 + 2d 13 + 2e 13 + 2f 13 + 30 13 + 31 13 + 34 14 + 35 14 + 36 14 + 37 14 + 38 14 + 3e 17 + 3f 17 + 40 17 + 41 17 + 42 17 + 43 17 + 44 17 + 45 17 + 46 17 + 47 17 + 48 17 + 49 17 + 4c 15 + 50 22 + 51 15 + } +} + +Lines mapping: +8 <-> 8 +9 <-> 9 +12 <-> 11 +14 <-> 13 diff --git a/testData/src/java8/pkg/TestArrayAssign.java b/testData/src/java8/pkg/TestArrayAssign.java new file mode 100644 index 0000000000..7f91218def --- /dev/null +++ b/testData/src/java8/pkg/TestArrayAssign.java @@ -0,0 +1,23 @@ +package pkg; + +public class TestArrayAssign { + public void test(Holder holder, int i, double inc) { + for (int j = 0; j < i; j++) { + holder.get()[j] += inc; + } + } + + public void test1(Holder holder, int i, double inc) { + for (int j = 0; j < i; j++) { + holder.a[j] += inc; + } + } + + public class Holder { + public double[] a; + + public double[] get() { + return a; + } + } +} diff --git a/testData/src/java8/pkg/TestDoWhileMerge.java b/testData/src/java8/pkg/TestDoWhileMerge.java new file mode 100644 index 0000000000..198707a51b --- /dev/null +++ b/testData/src/java8/pkg/TestDoWhileMerge.java @@ -0,0 +1,38 @@ +package pkg; + +public class TestDoWhileMerge { + // merging if conditions + public void test(boolean b, int j) { + for (int i = 0; i < j; i++) { + do { + System.out.println(i); + i++; + + if (i == 30) { + return; + } + } while (b && i < 40); + + System.out.println("test"); + } + + System.out.println("after"); + } + + public void test1(boolean b, int j) { + for (int i = 0; i < j; i++) { + System.out.println(1); + + do { + System.out.println(i); + i++; + + if (i == 30) { + return; + } + } while (b && i < 40); + } + + System.out.println("after"); + } +} diff --git a/testData/src/java8/pkg/TestForeachMultipleLoops.java b/testData/src/java8/pkg/TestForeachMultipleLoops.java new file mode 100644 index 0000000000..4e20415514 --- /dev/null +++ b/testData/src/java8/pkg/TestForeachMultipleLoops.java @@ -0,0 +1,41 @@ +package pkg; + +import java.util.Map; + +public class TestForeachMultipleLoops { + // Generates as multiple loops, continues turn into breaks + public void test(Object a, Map map, int i) { + if (a != null) { + System.out.println(a); + return; + } + + for (Map.Entry entry : map.entrySet()) { + String s = entry.getValue(); + if (a == null) { + s += s; + } else { + if ((s != null)) { + continue; + } + s = "hello"; + } + + Object v = entry.getValue(); + if (v == null) { + if (i == 3) { + continue; + } + System.out.println("if"); + } else { + System.out.println("else"); + } + + try { + System.out.println(1); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/testData/src/java8/pkg/TestLoopBreak3.java b/testData/src/java8/pkg/TestLoopBreak3.java new file mode 100644 index 0000000000..b7250e26eb --- /dev/null +++ b/testData/src/java8/pkg/TestLoopBreak3.java @@ -0,0 +1,25 @@ +package pkg; + +public class TestLoopBreak3 { + public void test(int i, boolean b) { + for (int j = 0; j < i; j++) { + System.out.println(j); + + for (int k = 0; k < j; k++) { + if (k == 2) { + for (int l = 0; l < 2; l++) { + System.out.println(2); + + if (b) { + System.out.println(l); + } else { + break; + } + } + + break; + } + } + } + } +} diff --git a/testData/src/java8/pkg/TestTernaryReturn.java b/testData/src/java8/pkg/TestTernaryReturn.java new file mode 100644 index 0000000000..8b3bfee30d --- /dev/null +++ b/testData/src/java8/pkg/TestTernaryReturn.java @@ -0,0 +1,16 @@ +package pkg; + +public class TestTernaryReturn { + public Object a; + public Object b; + + public boolean test(Object o) { + if (!(o instanceof TestTernaryReturn)) { + return false; + } + + TestTernaryReturn p = (TestTernaryReturn) o; + + return (a == null ? p.a == null : a.equals(p.a)) && (b == null ? p.b == null : b.equals(p.b)); + } +} From 6563bf98f9f6b23532ae1d3310b8b82c941584dd Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Mon, 29 Nov 2021 08:38:03 -0500 Subject: [PATCH 61/85] Make sure tests aren't registered twice --- test/org/jetbrains/java/decompiler/SingleClassesTest.java | 1 - .../jetbrains/java/decompiler/SingleClassesTestBase.java | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 290e1cf84a..20648ae6a2 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -169,7 +169,6 @@ private void registerDefault() { register(JAVA_8, "TestAccessReplace"); register(JAVA_8, "TestStringLiterals"); - register(JAVA_8, "TestClassFields"); register(JAVA_8, "TestClashName", "SharedName1", "SharedName2", "SharedName3", "SharedName4", "NonSharedName", "TestClashNameParent", "ext/TestClashNameParent", "TestClashNameIface", "ext/TestClashNameIface"); diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java index dd80019c2a..2e70205449 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTestBase.java @@ -40,6 +40,7 @@ public abstract class SingleClassesTestBase { private TestSet currentTestSet; private final List testSets = new ArrayList<>(); + private final Set classNames = new HashSet<>(); protected String[] getDecompilerOptions() { return new String[] {}; @@ -58,6 +59,11 @@ protected final void register(TestDefinition.Version version, String testClass, } private void register(TestDefinition.Version version, String testClass, boolean failable, String... others) { + if (classNames.contains(testClass)) { + throw new AssertionFailedError("Registered same class twice! " + testClass); + } + classNames.add(testClass); + List othersList = new ArrayList<>(others.length); for (String other : others) othersList.add(getFullClassName(other)); currentTestSet.testDefinitions.add(new TestDefinition(version, getFullClassName(testClass), othersList, failable)); From 7fae1db5f6061ade5b7ca8d0c483d8100e192149 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:35:50 -0500 Subject: [PATCH 62/85] Add more explanation for what replaceContinueWithBreak does --- .../modules/decompiler/LabelHelper.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java index d4b5253b95..ebf7f5f802 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java @@ -461,6 +461,34 @@ private static LabelSets processStatementLabel(Statement stat) { } // Handles switches in loops, so switch breaks don't become continues + // + // Also processes labeled continues to make them into breaks if they are the last statement inside the closure statement + // As so: + // + // label: + // while(...) { + // ... + // while(...) { + // ... + // if (...) { + // continue label; + // } + // } + // } + // + // will turn into + // + // while(...) { + // ... + // while(...) { + // ... + // if (...) { + // break; + // } + // } + // } + // + // This is only applicable when this is the last statement within it's parent nest as otherwise it'll be a jump to the next statement instead of a backjump to the loop public static boolean replaceContinueWithBreak(Statement stat) { boolean res = false; From 8f39259edacb9277635ff001f70d6460100ee176 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Mon, 29 Nov 2021 17:38:53 -0500 Subject: [PATCH 63/85] Improve switch expression processor --- .../decompiler/SwitchExpressionHelper.java | 241 +++++++++++++++--- 1 file changed, 201 insertions(+), 40 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java index c866a96043..f8a7db89af 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java @@ -5,8 +5,10 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.modules.decompiler.stats.*; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; +import org.jetbrains.java.decompiler.util.DotExporter; import java.util.*; +import java.util.stream.Collectors; public final class SwitchExpressionHelper { public static boolean processSwitchExpressions(Statement root) { @@ -39,56 +41,81 @@ private static boolean processStatement(SwitchStatement stat) { // At this stage, there are no variable assignments // So we need to figure out which variable, if any, this switch statement is an expression of and make it generate. - VarVersionPair foundVar = null; - VarExprent found = null; - for (Statement caseStat : stat.getCaseStatements()) { - Set edges = new HashSet<>(); - TryWithResourcesProcessor.findEdgesLeaving(caseStat, caseStat, edges); - for (StatEdge edge : edges) { - // There's a continue- can't be a switch expression - if (edge.getType() == StatEdge.TYPE_CONTINUE) { - return false; - } + + Exprent condition = ((SwitchHeadExprent) stat.getHeadexprent()).getValue(); + if (condition.type == Exprent.EXPRENT_INVOCATION) { + InvocationExprent invoc = (InvocationExprent) condition; + if (invoc.getName().equals("hashCode") && invoc.getClassname().equals("java/lang/String")) { + return false; // We don't want to make switch expressions yet as switch processing hasn't happened } + } - List exprents = caseStat.getExprents(); + // analyze all case statements with breaks to find the var we want. if it's found in all statements with breaks, and no other var is also found, we can make switch expressions + List breakJumps = findBreakJumps(stat); + if (breakJumps == null) { + return false; + } - // TODO: improve checking, possibly use SSA - if (exprents != null && !exprents.isEmpty()) { - Exprent exprent = exprents.get(exprents.size() - 1); + Set check = new HashSet<>(); + check.addAll(breakJumps); + check.addAll(stat.getCaseStatements()); - // We need all break edges to be enclosed in the current switch statement, as otherwise they could be breaking to statements beyond our scope, which messes up control flow - List breaks = caseStat.getSuccessorEdges(StatEdge.TYPE_BREAK); - if (breaks.isEmpty()) { - return false; // TODO: handle switch expression with fallthrough! - } + for (Statement st : check) { + if (!st.hasBasicSuccEdge()) { + continue; + } - if (exprent.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)exprent).getLeft().type == Exprent.EXPRENT_VAR) { - VarVersionPair var = (((VarExprent) ((AssignmentExprent) exprent).getLeft())).getVarVersionPair(); + List breaks = st.getSuccessorEdges(StatEdge.TYPE_BREAK); - if (breaks.get(0).closure != stat) { - return false; - } + if (breaks.isEmpty()) { + DotExporter.toDotFile(st.getTopParent(), "a"); + return false; // TODO: handle switch expression with fallthrough! + } - if (foundVar == null) { - foundVar = var; - found = (((VarExprent) ((AssignmentExprent) exprent).getLeft())); - } else { - if (!foundVar.equals(var)) { - return false; - } - } - } else if (exprent.type == Exprent.EXPRENT_EXIT && ((ExitExprent)exprent).getExitType() == ExitExprent.EXIT_RETURN) { - // TODO: check for successors to dummy exit! - return false; // Has a return, cannot be a switch statement - } + // If the closure isn't our statement and we're not returning, break + if (!stat.containsStatement(breaks.get(0).closure) && breaks.get(0).getDestination().type != Statement.TYPE_DUMMYEXIT) { + return false; + } + } + + Map> assignments = mapAssignments(breakJumps); + + // Must have found a return + if (assignments == null) { + return false; + } + + boolean foundDefault = false; + for (Statement statement : assignments.keySet()) { + if (stat.getDefaultEdge().getDestination().containsStatement(statement)) { + foundDefault = true; + break; } } - if (foundVar == null || found == null) { + // Need default always! + if (!foundDefault) { + return false; + } + + VarExprent relevantVar = findRelevantVar(assignments); + + if (relevantVar == null) { return false; } + for (Statement caseStat : stat.getCaseStatements()) { + Set edges = new HashSet<>(); + TryWithResourcesProcessor.findEdgesLeaving(caseStat, caseStat, edges); + + for (StatEdge edge : edges) { + // There's a continue- can't be a switch expression + if (edge.getType() == StatEdge.TYPE_CONTINUE) { + return false; + } + } + } + List sucs = stat.getSuccessorEdges(StatEdge.TYPE_REGULAR); // TODO: should we be using getbasichead? @@ -127,7 +154,7 @@ private static boolean processStatement(SwitchStatement stat) { for (Statement st : stat.getCaseStatements()) { Map replacements = new HashMap<>(); - findReplacements(st, foundVar, replacements); + findReplacements(st, relevantVar.getVarVersionPair(), replacements); // Replace exprents that we found if (!replacements.isEmpty()) { @@ -140,9 +167,9 @@ private static boolean processStatement(SwitchStatement stat) { List exprents = suc.getExprents(); - VarExprent vExpr = new VarExprent(found.getIndex(), found.getVarType(), found.getProcessor()); + VarExprent vExpr = new VarExprent(relevantVar.getIndex(), relevantVar.getVarType(), relevantVar.getProcessor()); vExpr.setStack(true); // We want to inline - AssignmentExprent toAdd = new AssignmentExprent(vExpr, new SwitchExprent(stat, found.getExprType(), false), null); + AssignmentExprent toAdd = new AssignmentExprent(vExpr, new SwitchExprent(stat, relevantVar.getExprType(), false), null); exprents.add(0, toAdd); @@ -200,6 +227,140 @@ private static void replace(Statement stat, Map replaceme } } + private static List findBreakJumps(SwitchStatement stat) { + List edges = stat.getSuccessorEdges(StatEdge.TYPE_REGULAR); + Statement check = stat.getParent(); + while (edges.isEmpty()) { + edges = check.getSuccessorEdges(StatEdge.TYPE_REGULAR); + check = check.getParent(); + + if (check == null) { + return null; + } + } + + StatEdge edge = edges.get(0); + Statement next = edge.getDestination(); + + List breaks = next.getPredecessorEdges(StatEdge.TYPE_BREAK); + + breaks.addAll(((RootStatement) stat.getTopParent()).getDummyExit().getPredecessorEdges(StatEdge.TYPE_BREAK)); + + // Remove breaks that didn't come from our switch statement nodes + breaks.removeIf(e -> !stat.containsStatement(e.getSource())); + + // Return all sources + return breaks.stream().map(StatEdge::getSource).collect(Collectors.toList()); + } + + // Find relevant assignments within blocks + // List is null if there is a throw. + private static Map> mapAssignments(List breakJumps) { + Map> map = new HashMap<>(); + + for (Statement breakJump : breakJumps) { + List exprents = breakJump.getExprents(); + + if (exprents != null && !exprents.isEmpty()) { + if (exprents.size() == 1 && exprents.get(0).type == Exprent.EXPRENT_EXIT) { + ExitExprent exit = ((ExitExprent) exprents.get(0)); + + // Special case throws + if (exit.getExitType() == ExitExprent.EXIT_THROW) { + map.put(breakJump, null); + continue; + } else { + return null; + } + } + + List list = new ArrayList<>(); + // Iterate in reverse, as we want the last assignment to be the one that we set the switch expression to + for (int i = exprents.size() - 1; i >= 0; i--) { + Exprent exprent = exprents.get(i); + if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { + AssignmentExprent assign = (AssignmentExprent) exprent; + + if (assign.getLeft().type == Exprent.EXPRENT_VAR) { + VarExprent var = ((VarExprent) assign.getLeft()); + + list.add(var.getVarVersionPair()); + continue; + } + } + break; + } + + map.put(breakJump, list); + } + } + + return map; + } + + // Null if none found + private static VarExprent findRelevantVar(Map> assignments) { + List> values = new ArrayList<>(assignments.values()); + + boolean consistentlyMoreThan1 = true; + + // Find any blocks with no assignments at all + for (List value : values) { + if (value == null) { + continue; + } + + if (value.isEmpty()) { + return null; + } + + if (value.size() == 1) { + consistentlyMoreThan1 = false; + } + } + + if (consistentlyMoreThan1) { + return null; + } + + List firstNotNull = null; + for (List value : values) { + if (value == null) { + continue; + } + + firstNotNull = value; + break; + } + + // Only made up of exceptions- quite funny but we should probably make a switch expression here? + if (firstNotNull == null) { + return null; + } + + VarVersionPair check = firstNotNull.get(0); + + for (List value : values) { + if (value == null) { + continue; + } + + if (!value.get(0).equals(check)) { + return null; + } + } + + for (Map.Entry> entry : assignments.entrySet()) { + if (entry.getValue() == firstNotNull) { + List exprents = entry.getKey().getExprents(); + Exprent exprent = exprents.get(exprents.size() - 1); + return ((VarExprent) ((AssignmentExprent) exprent).getLeft()); + } + } + + return null; + } + public static boolean hasSwitchExpressions(RootStatement statement) { return statement.mt.getBytecodeVersion().hasSwitchExpressions() && DecompilerContext.getOption(IFernflowerPreferences.SWITCH_EXPRESSIONS); } From 51b9316c3bced31949fc928c10f77eca23749afa Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 30 Nov 2021 08:20:06 -0500 Subject: [PATCH 64/85] More comments, less allocation --- .../modules/decompiler/SwitchExpressionHelper.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java index f8a7db89af..83c2991019 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchExpressionHelper.java @@ -5,7 +5,6 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.modules.decompiler.stats.*; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; -import org.jetbrains.java.decompiler.util.DotExporter; import java.util.*; import java.util.stream.Collectors; @@ -68,7 +67,6 @@ private static boolean processStatement(SwitchStatement stat) { List breaks = st.getSuccessorEdges(StatEdge.TYPE_BREAK); if (breaks.isEmpty()) { - DotExporter.toDotFile(st.getTopParent(), "a"); return false; // TODO: handle switch expression with fallthrough! } @@ -80,7 +78,7 @@ private static boolean processStatement(SwitchStatement stat) { Map> assignments = mapAssignments(breakJumps); - // Must have found a return + // Must have found a return if it's null if (assignments == null) { return false; } @@ -100,12 +98,13 @@ private static boolean processStatement(SwitchStatement stat) { VarExprent relevantVar = findRelevantVar(assignments); + // No var found if (relevantVar == null) { return false; } + Set edges = new HashSet<>(); for (Statement caseStat : stat.getCaseStatements()) { - Set edges = new HashSet<>(); TryWithResourcesProcessor.findEdgesLeaving(caseStat, caseStat, edges); for (StatEdge edge : edges) { @@ -114,6 +113,8 @@ private static boolean processStatement(SwitchStatement stat) { return false; } } + + edges.clear(); } List sucs = stat.getSuccessorEdges(StatEdge.TYPE_REGULAR); From 658a38ea944426fbd1e5e081014ee677fd294369 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 30 Nov 2021 13:38:35 -0500 Subject: [PATCH 65/85] Implement some missing exprent functionality --- .../decompiler/exps/SwitchExprent.java | 2 +- .../decompiler/exps/SwitchHeadExprent.java | 1 + .../modules/decompiler/exps/YieldExprent.java | 26 +++++++++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) 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 02d53d1bb6..42772bbb09 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -151,6 +151,6 @@ protected List getAllExprents(List list) { @Override public void getBytecodeRange(BitSet values) { - + measureBytecode(values); } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java index b7188d384c..a35c13155b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java @@ -47,6 +47,7 @@ public VarType getExprType() { public CheckTypesResult checkExprTypeBounds() { CheckTypesResult result = new CheckTypesResult(); + // TODO: this surely can't be right with switch on enum and string? result.addMinTypeExprent(value, VarType.VARTYPE_BYTECHAR); result.addMaxTypeExprent(value, VarType.VARTYPE_INT); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java index a3eef2083a..2295421557 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java @@ -1,7 +1,9 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; +import org.jetbrains.java.decompiler.code.CodeConstants; 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.gen.VarType; import org.jetbrains.java.decompiler.util.TextBuffer; @@ -9,7 +11,7 @@ import java.util.List; public class YieldExprent extends Exprent { - private final Exprent content; + private Exprent content; private final VarType retType; public YieldExprent(Exprent content, VarType retType) { @@ -29,6 +31,18 @@ public Exprent copy() { return new YieldExprent(this.content.copy(), this.retType); } + @Override + public CheckTypesResult checkExprTypeBounds() { + CheckTypesResult result = new CheckTypesResult(); + + if (retType.type != CodeConstants.TYPE_VOID) { + result.addMinTypeExprent(this.content, VarType.getMinTypeInFamily(retType.typeFamily)); + result.addMaxTypeExprent(this.content, retType); + } + + return result; + } + @Override public TextBuffer toJava(int indent) { TextBuffer buf = new TextBuffer(); @@ -42,6 +56,13 @@ public Exprent getContent() { return content; } + @Override + public void replaceExprent(Exprent oldExpr, Exprent newExpr) { + if (oldExpr == this.content) { + this.content = newExpr; + } + } + @Override public VarType getExprType() { return this.retType; @@ -49,6 +70,7 @@ public VarType getExprType() { @Override public void getBytecodeRange(BitSet values) { - + measureBytecode(values, this.content); + measureBytecode(values); } } From 50229e762c6b24592cd494b9abbdc9e32dd6a75b Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Tue, 30 Nov 2021 18:56:28 -0500 Subject: [PATCH 66/85] A few more tests --- .../decompiler/exps/SwitchHeadExprent.java | 1 - .../java/decompiler/SingleClassesTest.java | 2 + .../pkg/TestConstructorSwitchExpression3.dec | 91 +++++++++++++++++++ .../results/pkg/TestSwitchExpressionPPMM.dec | 75 +++++++++++++++ .../pkg/TestConstructorSwitchExpression3.java | 24 +++++ .../java16/pkg/TestSwitchExpressionPPMM.java | 17 ++++ 6 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 testData/results/pkg/TestConstructorSwitchExpression3.dec create mode 100644 testData/results/pkg/TestSwitchExpressionPPMM.dec create mode 100644 testData/src/java16/pkg/TestConstructorSwitchExpression3.java create mode 100644 testData/src/java16/pkg/TestSwitchExpressionPPMM.java diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java index a35c13155b..de13045dc1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java @@ -3,7 +3,6 @@ */ package org.jetbrains.java.decompiler.modules.decompiler.exps; -import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 6e43d60fe1..c4147c5341 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -345,6 +345,8 @@ private void registerDefault() { register(JAVA_16, "TestConstructorSwitchExpression2"); register(JAVA_16, "TestAssertSwitchExpression"); register(JAVA_16, "TestSwitchExpressionFallthrough1"); + register(JAVA_16, "TestConstructorSwitchExpression3"); + register(JAVA_16, "TestSwitchExpressionPPMM"); register(JAVA_16_PREVIEW, "TestSealedClasses"); register(JAVA_16_PREVIEW, "PermittedSubClassA", "TestSealedClasses"); diff --git a/testData/results/pkg/TestConstructorSwitchExpression3.dec b/testData/results/pkg/TestConstructorSwitchExpression3.dec new file mode 100644 index 0000000000..bd51435ada --- /dev/null +++ b/testData/results/pkg/TestConstructorSwitchExpression3.dec @@ -0,0 +1,91 @@ +package pkg; + +import java.util.Random; + +public enum TestConstructorSwitchExpression3 { + T1, + T2; + + private TestConstructorSwitchExpression3(int i) { + System.out.println(i);// 18 + }// 19 + + private static int get() { + return (new Random()).nextInt(3);// 22 + } + + static { + T1 = new TestConstructorSwitchExpression3(switch(get()) {// 6 + case 0 -> 1;// 7 + case 1 -> 2;// 8 + default -> 3;// 9 + }); + + T2 = new TestConstructorSwitchExpression3(switch(get()) {// 11 + case 0 -> 1;// 12 + case 1 -> 2;// 13 + default -> 3;// 14 + }); + }// 5 +} + +class 'pkg/TestConstructorSwitchExpression3' { + method ' (Ljava/lang/String;II)V' { + 6 9 + 7 9 + 8 9 + 9 9 + a 9 + b 9 + c 9 + d 10 + } + + method 'get ()I' { + 7 13 + 8 13 + 9 13 + a 13 + b 13 + } + + method ' ()V' { + 7 17 + 8 17 + 9 17 + a 17 + 24 18 + 28 19 + 2c 20 + 30 17 + 31 17 + 32 17 + 3a 23 + 3b 23 + 3c 23 + 3d 23 + 58 24 + 5c 25 + 60 26 + 64 23 + 65 23 + 66 23 + 6d 28 + } +} + +Lines mapping: +5 <-> 29 +6 <-> 18 +7 <-> 19 +8 <-> 20 +9 <-> 21 +11 <-> 24 +12 <-> 25 +13 <-> 26 +14 <-> 27 +18 <-> 10 +19 <-> 11 +22 <-> 14 +Not mapped: +17 diff --git a/testData/results/pkg/TestSwitchExpressionPPMM.dec b/testData/results/pkg/TestSwitchExpressionPPMM.dec new file mode 100644 index 0000000000..fdd86748ee --- /dev/null +++ b/testData/results/pkg/TestSwitchExpressionPPMM.dec @@ -0,0 +1,75 @@ +package pkg; + +public class TestSwitchExpressionPPMM { + public int test(int test, int x) { + System.out.println(x);// 5 + + int i = 1 + switch(test) {// 6 + case 1 -> x++;// 7 + case 2 -> { + ++x;// 8 + yield x; + } + case 3 -> x--;// 9 + case 4 -> { + --x;// 10 + yield x; + } + default -> x;// 11 + }; + System.out.println(x);// 14 + return i;// 15 + } +} + +class 'pkg/TestSwitchExpressionPPMM' { + method 'test (II)I' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 6 4 + 7 6 + 8 6 + 9 6 + 29 7 + 2a 7 + 2b 7 + 2f 9 + 30 9 + 31 9 + 32 10 + 37 12 + 38 12 + 39 12 + 3d 14 + 3e 14 + 3f 14 + 40 15 + 44 17 + 45 6 + 46 6 + 47 19 + 48 19 + 49 19 + 4a 19 + 4b 19 + 4c 19 + 4d 19 + 4e 20 + 4f 20 + } +} + +Lines mapping: +5 <-> 5 +6 <-> 7 +7 <-> 8 +8 <-> 10 +9 <-> 13 +10 <-> 15 +11 <-> 18 +14 <-> 20 +15 <-> 21 diff --git a/testData/src/java16/pkg/TestConstructorSwitchExpression3.java b/testData/src/java16/pkg/TestConstructorSwitchExpression3.java new file mode 100644 index 0000000000..e0329d8b19 --- /dev/null +++ b/testData/src/java16/pkg/TestConstructorSwitchExpression3.java @@ -0,0 +1,24 @@ +package pkg; + +import java.util.Random; + +public enum TestConstructorSwitchExpression3 { + T1(switch (get()) { + case 0 -> 1; + case 1 -> 2; + default -> 3; + }), + T2(switch (get()) { + case 0 -> 1; + case 1 -> 2; + default -> 3; + }); + + TestConstructorSwitchExpression3(int i) { + System.out.println(i); + } + + private static int get() { + return new Random().nextInt(3); + } +} diff --git a/testData/src/java16/pkg/TestSwitchExpressionPPMM.java b/testData/src/java16/pkg/TestSwitchExpressionPPMM.java new file mode 100644 index 0000000000..732e5f02c8 --- /dev/null +++ b/testData/src/java16/pkg/TestSwitchExpressionPPMM.java @@ -0,0 +1,17 @@ +package pkg; + +public class TestSwitchExpressionPPMM { + public int test(int test, int x) { + System.out.println(x); + int i = 1 + switch (test) { + case 1 -> x++; + case 2 -> ++x; + case 3 -> x--; + case 4 -> --x; + default -> x; + }; + + System.out.println(x); + return i; + } +} From 191edb1f9e6d5f9ce184e63d882a82e0c4dd2fa3 Mon Sep 17 00:00:00 2001 From: SuperCoder79 <25208576+SuperCoder7979@users.noreply.github.com> Date: Wed, 1 Dec 2021 09:21:52 -0500 Subject: [PATCH 67/85] Update readme some more --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6fb8265313..99615199ae 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,19 @@ Changes include: - Optimization - Many other miscellaneous features and fixes -For support or questions, please join the [Quilt toolchain discord.](https://discord.quiltmc.org/toolchain) +### Use +Want to use Quiltflower? There are a few ways! For Fabric and Architectury projects, [Loom Quiltflower](https://github.com/Juuxel/LoomQuiltflower) allows you to run genSources with Quiltflower. +The [Quiltflower Intellij IDEA plugin](https://plugins.jetbrains.com/plugin/18032-quiltflower) replaces Fernflower in IDEA with Quiltflower, and allows you to modify its settings. +Or, if you want to run Quiltflower from the commandline, head over to the [Releases tab](https://github.com/QuiltMC/quiltflower/releases) and grab the latest, and then follow the instructions further down the readme. +Make sure to report any issues to the [Issues tab!](https://github.com/QuiltMC/quiltflower/issues) -When pulling from upstream, use https://github.com/fesh0r/fernflower +For support or questions, please join the [Quilt toolchain discord.](https://discord.quiltmc.org/toolchain) ### Contributing To contribute, please check out [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHITECTURE.md](./ARCHITECTURE.md)! +When pulling from upstream, use https://github.com/fesh0r/fernflower + #### Special Thanks * Jetbrains- For maintaining Fernflower * Forge Team- For maintaining ForgeFlower @@ -30,7 +36,7 @@ Fernflower's readme is preserved below: Fernflower is the first actually working analytical decompiler for Java and probably for a high-level programming language in general. Naturally it is still under development, please send your bug reports and improvement suggestions to the -[issue tracker](https://youtrack.jetbrains.com/newIssue?project=IDEA&clearDraft=true&c=Subsystem+Decompiler). +[issue tracker](https://github.com/QuiltMC/quiltflower/issues). ### Licence @@ -38,7 +44,7 @@ Fernflower is licenced under the [Apache Licence Version 2.0](http://www.apache. ### Running from command line -`java -jar fernflower.jar [-