当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