当switch里面包含方法调用时,反编译会报错:
java.lang.NullPointerException: Cannot read field "type" because the return value of "org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent.getInstance()" is null at org.jetbrains.java.decompiler.modules.decompiler.SwitchHelper$StringSwitchRecognizer$JavacStringRecognizer.recognize(SwitchHelper.java:427) at org.jetbrains.java.decompiler.modules.decompiler.SwitchHelper$StringSwitchRecognizer$JavacStringRecognizer.recognize(SwitchHelper.java:404) at org.jetbrains.java.decompiler.modules.decompiler.SwitchHelper.collectSwitchesOn(SwitchHelper.java:130) at org.jetbrains.java.decompiler.modules.decompiler.SwitchHelper.collectSwitchesOn(SwitchHelper.java:139) at org.jetbrains.java.decompiler.modules.decompiler.SwitchHelper.simplifySwitchesOnReferences(SwitchHelper.java:59) at org.jetbrains.java.decompiler.main.rels.MethodProcessorRunnable.codeToJava(MethodProcessorRunnable.java:216) at org.jetbrains.java.decompiler.main.rels.MethodProcessorRunnable.run(MethodProcessorRunnable.java:55) at org.jetbrains.java.decompiler.main.rels.ClassWrapper.init(ClassWrapper.java:73) at org.jetbrains.java.decompiler.main.ClassesProcessor.initWrappers(ClassesProcessor.java:396) at org.jetbrains.java.decompiler.main.ClassesProcessor.writeClass(ClassesProcessor.java:350) at org.jetbrains.java.decompiler.main.Fernflower.getClassContent(Fernflower.java:123) at org.jetbrains.java.decompiler.struct.ContextUnit.save(ContextUnit.java:100) at org.jetbrains.java.decompiler.struct.StructContext.saveContext(StructContext.java:57) at org.jetbrains.java.decompiler.main.Fernflower.decompileContext(Fernflower.java:96) at org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.decompileContext(ConsoleDecompiler.java:126) at org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(ConsoleDecompiler.java:83)
在官方YouTrack上提了一个issue(https://youtrack.jetbrains.com/issue/IDEA-346717/Decompiler-fails-to-decompile-switch-statements-containing-static-method-calls),不过一周过去了好像也没有回应,干脆自己研究一下。
测试用例:
public class A { public static void main(String[] args) { a(); b(); c(); } public static void a() { switch (aa()) { case "1": System.out.println("a"); break; case "2": System.out.println("b"); break; } } public static String aa() { return "1"; } public static void b() { switch (bb()) { case 1: System.out.println("a"); break; case 2: System.out.println("b"); break; } } public static int bb() { return 1; } public static void c() { switch (new A().cc()) { case 1: System.out.println("a"); break; case 2: System.out.println("b"); break; } } public int cc() { return 1; } }
其中,a()和c()能够正常反编译,而b()不行。发现是调用静态方法导致的。
在Fernflower中,如果是静态调用,那么InvocationExprent的instance成员变量为null(InvocationExprent.java:121):
else if (opcode == CodeConstants.opc_invokestatic) { isStatic = true; } else { instance = stack.pop(); }
而在处理switch时,会获取InvocationExprent的instance成员的type成员(SwitchHelper.java:427):
if (switchSelector.getInstance().type != Exprent.EXPRENT_VAR) return null;
此时,如果instance是null,就会报错。解决方法为直接先在前面判断instance是否为null:
if (switchSelector.getInstance() == null || switchSelector.getInstance().type != Exprent.EXPRENT_VAR) return null;
提交了一个PR,目前已修复(就是不知道什么时候release新版本):https://github.com/JetBrains/intellij-community/pull/2688