From 2431c0fe94029c3e8f76cae957b798baa05b88fa Mon Sep 17 00:00:00 2001 From: upnotes Date: Fri, 10 Aug 2018 14:59:17 +0200 Subject: [PATCH] Hiding default constructor with respect to its access modifiers --- .../java/decompiler/main/ClassWriter.java | 20 ++++++++++++-- .../java/decompiler/SingleClassesTest.java | 1 + .../pkg/TestPrivateEmptyConstructor.class | Bin 0 -> 420 bytes .../results/TestPrivateEmptyConstructor.dec | 26 ++++++++++++++++++ .../src/pkg/TestPrivateEmptyConstructor.java | 10 +++++++ 5 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 testData/classes/pkg/TestPrivateEmptyConstructor.class create mode 100644 testData/results/TestPrivateEmptyConstructor.dec create mode 100644 testData/src/pkg/TestPrivateEmptyConstructor.java diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index a19bb36..42ef5f4 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -820,7 +820,7 @@ public class ClassWriter { BytecodeMappingTracer codeTracer = new BytecodeMappingTracer(tracer.getCurrentSourceLine()); TextBuffer code = root.toJava(indent + 1, codeTracer); - hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0; + hideMethod = (code.length() == 0) && (clinit || dinit || hideConstructor(node, init, throwsExceptions, paramCount, flags)); buffer.append(code); @@ -859,13 +859,25 @@ public class ClassWriter { return !hideMethod; } - private static boolean hideConstructor(ClassWrapper wrapper, boolean init, boolean throwsExceptions, int paramCount) { + private static boolean hideConstructor(ClassNode node, boolean init, boolean throwsExceptions, int paramCount, int methodAccessFlags) { + if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) { return false; } + ClassWrapper wrapper = node.getWrapper(); + StructClass cl = wrapper.getClassStruct(); + + int classAccesFlags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access; + boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); + + // default constructor requires same accessibility flags. Exception: enum constructor which is always private + if(!isEnum && ((classAccesFlags & ACCESSIBILITY_FLAGS) != (methodAccessFlags & ACCESSIBILITY_FLAGS))) { + return false; + } + int count = 0; - for (StructMethod mt : wrapper.getClassStruct().getMethods()) { + for (StructMethod mt : cl.getMethods()) { if (CodeConstants.INIT_NAME.equals(mt.getName())) { if (++count > 1) { return false; @@ -1031,6 +1043,8 @@ public class ClassWriter { private static final int FIELD_EXCLUDED = CodeConstants.ACC_PUBLIC | CodeConstants.ACC_STATIC | CodeConstants.ACC_FINAL; private static final int METHOD_EXCLUDED = CodeConstants.ACC_PUBLIC | CodeConstants.ACC_ABSTRACT; + private static final int ACCESSIBILITY_FLAGS = CodeConstants.ACC_PUBLIC | CodeConstants.ACC_PROTECTED | CodeConstants.ACC_PRIVATE; + private static void appendModifiers(TextBuffer buffer, int flags, int allowed, boolean isInterface, int excluded) { flags &= allowed; if (!isInterface) excluded = 0; diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index eb0cc2a..c8a7cad 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -108,6 +108,7 @@ public class SingleClassesTest { @Test public void testMissingConstructorCallGood() { doTest("pkg/TestMissingConstructorCallGood"); } @Test public void testMissingConstructorCallBad() { doTest("pkg/TestMissingConstructorCallBad"); } @Test public void testEmptyBlocks() { doTest("pkg/TestEmptyBlocks"); } + @Test public void testPrivateEmptyConstructor() { doTest("pkg/TestPrivateEmptyConstructor"); } // TODO: fix all below diff --git a/testData/classes/pkg/TestPrivateEmptyConstructor.class b/testData/classes/pkg/TestPrivateEmptyConstructor.class new file mode 100644 index 0000000000000000000000000000000000000000..cf452491f39304de763af86a8a2538f6d1e63ad1 GIT binary patch literal 420 zcmaJ-O-sW-5Ph4bNs~rfTkBU5ya;U%2Ekj!OVLwNA*J_CT*{VYQ<6=gKT8h^9{d6R zC~*=&J&3!oGyCSfna8|;yuJarK;MOhZ3iv18)&-NLB~ed#x8?(DV5Y$47I^<&R|Z` z2f@&qN+oWKBox_tv-jlT_t8D ()V' { + 4 2 + } + + method 'test ()V' { + 0 5 + 3 5 + 5 5 + 8 6 + } +} + +Lines mapping: +4 <-> 3 +7 <-> 6 +8 <-> 7 diff --git a/testData/src/pkg/TestPrivateEmptyConstructor.java b/testData/src/pkg/TestPrivateEmptyConstructor.java new file mode 100644 index 0000000..2a54b6a --- /dev/null +++ b/testData/src/pkg/TestPrivateEmptyConstructor.java @@ -0,0 +1,10 @@ + +public final class PrivateEmptyConstructor { + + private PrivateEmptyConstructor() {} + + public final void test() { + System.out.println("test"); + } +} +