diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java b/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java index 3fa8128..2ea32bd 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -29,10 +29,7 @@ import org.jetbrains.java.decompiler.struct.StructMethod; import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; import org.jetbrains.java.decompiler.util.InterpreterUtil; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map; +import java.util.*; public class NestedMemberAccess { @@ -40,6 +37,7 @@ public class NestedMemberAccess { private static final int METHOD_ACCESS_FIELD_GET = 2; private static final int METHOD_ACCESS_FIELD_SET = 3; private static final int METHOD_ACCESS_METHOD = 4; + private static final int METHOD_ACCESS_FUNCTION = 5; private boolean noSynthFlag; private final Map mapMethodType = new HashMap(); @@ -117,6 +115,16 @@ public class NestedMemberAccess { } } + break; + case Exprent.EXPRENT_FUNCTION: + // for now detect only increment/decrement + FunctionExprent functionExprent = (FunctionExprent)exprCore; + if (functionExprent.getFuncType() >= FunctionExprent.FUNCTION_IMM && + functionExprent.getFuncType() <= FunctionExprent.FUNCTION_PPI) { + if (functionExprent.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) { + type = METHOD_ACCESS_FUNCTION; + } + } break; case Exprent.EXPRENT_INVOCATION: type = METHOD_ACCESS_METHOD; @@ -139,7 +147,6 @@ public class NestedMemberAccess { } } - if (type == METHOD_ACCESS_METHOD) { // FIXME: check for private flag of the method type = METHOD_ACCESS_NORMAL; @@ -323,7 +330,6 @@ public class NestedMemberAccess { } private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) { - ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(invexpr.getClassname()); MethodWrapper methsource = null; @@ -408,6 +414,9 @@ public class NestedMemberAccess { } retexprent = ret; break; + case METHOD_ACCESS_FUNCTION: + retexprent = replaceFunction(invexpr, source); + break; case METHOD_ACCESS_METHOD: if (source.type == Exprent.EXPRENT_EXIT) { source = ((ExitExprent)source).getValue(); @@ -446,4 +455,25 @@ public class NestedMemberAccess { return retexprent; } + + private static Exprent replaceFunction(final InvocationExprent invexpr, final Exprent source) { + FunctionExprent functionExprent = (FunctionExprent)((ExitExprent)source).getValue().copy(); + + List lstParameters = invexpr.getLstParameters(); + + FieldExprent fieldExprent = (FieldExprent)functionExprent.getLstOperands().get(0); + if (fieldExprent.isStatic()) { + if (!lstParameters.isEmpty()) { + return null; + } + return functionExprent; + } + + if (lstParameters.size() != 1) { + return null; + } + + fieldExprent.replaceExprent(fieldExprent.getInstance(), lstParameters.get(0)); + return functionExprent; + } } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 100deeb..5bdbdc5 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -85,8 +85,9 @@ public class SingleClassesTest { @Test public void testMemberAnnotations() { doTest("pkg/TestMemberAnnotations"); } @Test public void testStaticNameClash() { doTest("pkg/TestStaticNameClash"); } @Test public void testExtendingSubclass() { doTest("pkg/TestExtendingSubclass"); } + @Test public void testSyntheticAccess() { doTest("pkg/TestSyntheticAccess"); } - protected void doTest(String testFile, String... companionFiles) { + private void doTest(String testFile, String... companionFiles) { ConsoleDecompiler decompiler = fixture.getDecompiler(); File classFile = new File(fixture.getTestDataDir(), "/classes/" + testFile + ".class"); @@ -131,4 +132,4 @@ public class SingleClassesTest { return files; } -} \ No newline at end of file +} diff --git a/testData/classes/pkg/TestSyntheticAccess$Assigner.class b/testData/classes/pkg/TestSyntheticAccess$Assigner.class new file mode 100644 index 0000000..c15e644 Binary files /dev/null and b/testData/classes/pkg/TestSyntheticAccess$Assigner.class differ diff --git a/testData/classes/pkg/TestSyntheticAccess$Incrementer.class b/testData/classes/pkg/TestSyntheticAccess$Incrementer.class new file mode 100644 index 0000000..631d437 Binary files /dev/null and b/testData/classes/pkg/TestSyntheticAccess$Incrementer.class differ diff --git a/testData/classes/pkg/TestSyntheticAccess.class b/testData/classes/pkg/TestSyntheticAccess.class new file mode 100644 index 0000000..b4e05e6 Binary files /dev/null and b/testData/classes/pkg/TestSyntheticAccess.class differ diff --git a/testData/results/TestSyntheticAccess.dec b/testData/results/TestSyntheticAccess.dec new file mode 100644 index 0000000..1f8a5d5 --- /dev/null +++ b/testData/results/TestSyntheticAccess.dec @@ -0,0 +1,85 @@ +package pkg; + +class TestSyntheticAccess { + private static int s; + private int i; + + private class Assigner { + void assignI(int newValue) { + TestSyntheticAccess.this.i = newValue;// 32 + }// 33 + + void assignS(int newValue) { + TestSyntheticAccess.s = newValue;// 36 + }// 37 + } + + private class Incrementer { + void incrementI() { + TestSyntheticAccess.this.i++;// 14 + }// 15 + + void decrementI() { + --TestSyntheticAccess.this.i;// 18 + }// 19 + + void incrementS() { + ++TestSyntheticAccess.s;// 22 23 + } + + void decrementS() { + TestSyntheticAccess.s--;// 26 + }// 27 + } +} + +class 'pkg/TestSyntheticAccess$Assigner' { + method 'assignI (I)V' { + 3 8 + 9 9 + } + + method 'assignS (I)V' { + 2 12 + 5 13 + } +} + +class 'pkg/TestSyntheticAccess$Incrementer' { + method 'incrementI ()V' { + 2 18 + 7 18 + 8 19 + } + + method 'decrementI ()V' { + 2 22 + 6 22 + 8 23 + } + + method 'incrementS ()V' { + 0 26 + 4 26 + } + + method 'decrementS ()V' { + 0 30 + 4 31 + 5 30 + } +} + +Lines mapping: +14 <-> 19 +15 <-> 20 +18 <-> 23 +19 <-> 24 +22 <-> 27 +23 <-> 27 +26 <-> 31 +27 <-> 32 +32 <-> 9 +33 <-> 10 +36 <-> 13 +37 <-> 14 diff --git a/testData/src/pkg/TestSyntheticAccess.java b/testData/src/pkg/TestSyntheticAccess.java new file mode 100644 index 0000000..0c4e3ea --- /dev/null +++ b/testData/src/pkg/TestSyntheticAccess.java @@ -0,0 +1,44 @@ +package pkg; + +/** + * @author Alexandru-Constantin Bledea + * @since March 20, 2016 + */ +class TestSyntheticAccess { + + private static int s; + private int i; + + private class Incrementer { + void orI() { + i|=1; + } + + void incrementI() { + i++; + } + + void decrementI() { + --i; + } + + void incrementS() { + ++s; + } + + void decrementS() { + s--; + } + } + + private class Assigner { + void assignI(int newValue) { + i = newValue; + } + + void assignS(int newValue) { + s = newValue; + } + } + +}