java-decompiler: extra casts on method calls omitted

(loosely based on https://github.com/JetBrains/intellij-community/pull/217)
This commit is contained in:
Roman Shevchenko 2014-11-04 11:30:23 +01:00
parent 38f1a1a9ee
commit 020f5c404b
9 changed files with 104 additions and 39 deletions

View File

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

View File

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

View File

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

Binary file not shown.

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

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

View File

@ -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");
}
}