java-decompiler: extra casts on method calls omitted

(loosely based on https://github.com/JetBrains/intellij-community/pull/217)
master
Roman Shevchenko 10 years ago
parent 38f1a1a9ee
commit 020f5c404b
  1. 81
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java
  2. 2
      src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java
  3. 2
      test/org/jetbrains/java/decompiler/SingleClassesTest.java
  4. BIN
      testData/classes/pkg/TestAmbiguousCall.class
  5. BIN
      testData/classes/pkg/TestAmbiguousCallWithDebugInfo.class
  6. 18
      testData/results/TestAmbiguousCall.dec
  7. 18
      testData/results/TestAmbiguousCallWithDebugInfo.dec
  8. 2
      testData/results/TestEnum.dec
  9. 16
      testData/src/pkg/TestAmbiguousCall.java

@ -53,6 +53,8 @@ public class InvocationExprent extends Exprent {
public static final int CONSTRUCTOR_THIS = 1; public static final int CONSTRUCTOR_THIS = 1;
public static final int CONSTRUCTOR_SUPER = 2; public static final int CONSTRUCTOR_SUPER = 2;
private static final BitSet EMPTY_BIT_SET = new BitSet(0);
private String name; private String name;
private String classname; private String classname;
@ -321,7 +323,7 @@ public class InvocationExprent extends Exprent {
break; break;
case TYP_CLINIT: case TYP_CLINIT:
throw new RuntimeException("Explicite invocation of <clinit>"); throw new RuntimeException("Explicit invocation of <clinit>");
case TYP_INIT: case TYP_INIT:
if (super_qualifier != null) { if (super_qualifier != null) {
buf.append("super("); buf.append("super(");
@ -355,7 +357,7 @@ public class InvocationExprent extends Exprent {
} }
} }
Set<Integer> setAmbiguousParameters = getAmbiguousParameters(); BitSet setAmbiguousParameters = getAmbiguousParameters();
boolean firstParameter = true; boolean firstParameter = true;
int start = isEnum ? 2 : 0; int start = isEnum ? 2 : 0;
@ -366,7 +368,7 @@ public class InvocationExprent extends Exprent {
} }
TextBuffer buff = new TextBuffer(); TextBuffer buff = new TextBuffer();
boolean ambiguous = setAmbiguousParameters.contains(i); boolean ambiguous = setAmbiguousParameters.get(i);
ExprProcessor.getCastedExprent(lstParameters.get(i), descriptor.params[i], buff, indent, true, ambiguous, tracer); ExprProcessor.getCastedExprent(lstParameters.get(i), descriptor.params[i], buff, indent, true, ambiguous, tracer);
buf.append(buff); buf.append(buff);
@ -379,47 +381,56 @@ public class InvocationExprent extends Exprent {
return buf; return buf;
} }
private Set<Integer> getAmbiguousParameters() { private BitSet getAmbiguousParameters() {
StructClass cl = DecompilerContext.getStructContext().getClass(classname);
Set<Integer> ret = new HashSet<Integer>(); if (cl == null) return EMPTY_BIT_SET;
StructClass cstr = DecompilerContext.getStructContext().getClass(classname); // check number of matches
if (cstr != null) { List<MethodDescriptor> matches = new ArrayList<MethodDescriptor>();
List<MethodDescriptor> lstMethods = new ArrayList<MethodDescriptor>(); nextMethod:
for (StructMethod meth : cstr.getMethods()) { for (StructMethod mt : cl.getMethods()) {
if (name.equals(meth.getName())) { if (name.equals(mt.getName())) {
MethodDescriptor md = MethodDescriptor.parseDescriptor(meth.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
if (md.params.length == descriptor.params.length) { if (md.params.length == descriptor.params.length) {
boolean equals = true; for (int i = 0; i < md.params.length; i++) {
for (int i = 0; i < md.params.length; i++) { if (md.params[i].type_family != descriptor.params[i].type_family) {
if (md.params[i].type_family != descriptor.params[i].type_family) { continue nextMethod;
equals = false;
break;
}
}
if (equals) {
lstMethods.add(md);
} }
} }
matches.add(md);
} }
} }
}
if (lstMethods.size() > 1) { if (matches.size() == 1) return EMPTY_BIT_SET;
for (int i = 0; i < descriptor.params.length; i++) {
VarType partype = descriptor.params[i]; // check if a call is unambiguous
StructMethod mt = cl.getMethod(InterpreterUtil.makeUniqueKey(name, stringDescriptor));
for (MethodDescriptor md : lstMethods) { if (mt != null) {
if (!partype.equals(md.params[i])) { MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
ret.add(i); if (md.params.length == lstParameters.size()) {
break; boolean exact = true;
} for (int i = 0; i < md.params.length; i++) {
if (!md.params[i].equals(lstParameters.get(i).getExprType())) {
exact = false;
break;
} }
} }
if (exact) return EMPTY_BIT_SET;
} }
} }
return ret; // mark parameters
BitSet ambiguous = new BitSet(descriptor.params.length);
for (int i = 0; i < descriptor.params.length; i++) {
VarType paramType = descriptor.params[i];
for (MethodDescriptor md : matches) {
if (!paramType.equals(md.params[i])) {
ambiguous.set(i);
break;
}
}
}
return ambiguous;
} }
public boolean equals(Object o) { public boolean equals(Object o) {

@ -35,7 +35,7 @@ import java.util.Map;
*/ */
public class StructLocalVariableTableAttribute extends StructGeneralAttribute { public class StructLocalVariableTableAttribute extends StructGeneralAttribute {
private Map<Integer, String> mapVarNames = new HashMap<Integer, String>(); private Map<Integer, String> mapVarNames = Collections.emptyMap();
@Override @Override
public void initContent(ConstantPool pool) throws IOException { public void initContent(ConstantPool pool) throws IOException {

@ -37,4 +37,6 @@ public class SingleClassesTest extends SingleClassesTestBase {
@Test public void testInnerClassConstructor() { doTest("pkg/TestInnerClassConstructor"); } @Test public void testInnerClassConstructor() { doTest("pkg/TestInnerClassConstructor"); }
@Test public void testInnerClassConstructor11() { doTest("v11/TestInnerClassConstructor"); } @Test public void testInnerClassConstructor11() { doTest("v11/TestInnerClassConstructor"); }
@Test public void testTryCatchFinally() { doTest("pkg/TestTryCatchFinally"); } @Test public void testTryCatchFinally() { doTest("pkg/TestTryCatchFinally"); }
@Test public void testAmbiguousCall() { doTest("pkg/TestAmbiguousCall"); }
@Test public void testAmbiguousCallWithDebugInfo() { doTest("pkg/TestAmbiguousCallWithDebugInfo"); }
} }

@ -0,0 +1,18 @@
package pkg;
class TestAmbiguousCall {
void m1(RuntimeException var1, String var2) {
}
void m1(IllegalArgumentException var1, String var2) {
}
void test() {
IllegalArgumentException var1 = new IllegalArgumentException();
this.m1((RuntimeException)var1, "RE");
this.m1(var1, "IAE");
IllegalArgumentException var2 = new IllegalArgumentException();
this.m1((RuntimeException)var2, "RE");
this.m1((IllegalArgumentException)var2, "IAE");
}
}

@ -0,0 +1,18 @@
package pkg;
class TestAmbiguousCall {
void m1(RuntimeException e, String s) {
}
void m1(IllegalArgumentException e, String s) {
}
void test() {
IllegalArgumentException iae = new IllegalArgumentException();
this.m1((RuntimeException)iae, "RE");
this.m1(iae, "IAE");
IllegalArgumentException re = new IllegalArgumentException();
this.m1((RuntimeException)re, "RE");
this.m1((IllegalArgumentException)re, "IAE");
}
}

@ -18,7 +18,7 @@ public enum TestEnum {
} }
private TestEnum() { private TestEnum() {
this((String)"?"); this("?");
} }
private TestEnum(@Deprecated String var3) { private TestEnum(@Deprecated String var3) {

@ -0,0 +1,16 @@
package pkg;
class TestAmbiguousCall {
void m1(RuntimeException e, String s) { }
void m1(IllegalArgumentException e, String s) { }
void test() {
IllegalArgumentException iae = new IllegalArgumentException();
m1((RuntimeException)iae, "RE");
m1(iae, "IAE");
RuntimeException re = new IllegalArgumentException();
m1(re, "RE");
m1((IllegalArgumentException)re, "IAE");
}
}
Loading…
Cancel
Save