diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java index b80b745..d7d2d76 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -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 "); + throw new RuntimeException("Explicit invocation of "); case TYP_INIT: if (super_qualifier != null) { buf.append("super("); @@ -355,7 +357,7 @@ public class InvocationExprent extends Exprent { } } - Set 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 getAmbiguousParameters() { - - Set ret = new HashSet(); - - StructClass cstr = DecompilerContext.getStructContext().getClass(classname); - if (cstr != null) { - List lstMethods = new ArrayList(); - 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); + private BitSet getAmbiguousParameters() { + StructClass cl = DecompilerContext.getStructContext().getClass(classname); + if (cl == null) return EMPTY_BIT_SET; + + // check number of matches + List matches = new ArrayList(); + 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 (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; - } + } + if (matches.size() == 1) return EMPTY_BIT_SET; + + // 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; } } - 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) { diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java index 60e40c0..fceae35 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java @@ -35,7 +35,7 @@ import java.util.Map; */ public class StructLocalVariableTableAttribute extends StructGeneralAttribute { - private Map mapVarNames = new HashMap(); + private Map mapVarNames = Collections.emptyMap(); @Override public void initContent(ConstantPool pool) throws IOException { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 20d4fa8..c1b36de 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -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"); } } diff --git a/testData/classes/pkg/TestAmbiguousCall.class b/testData/classes/pkg/TestAmbiguousCall.class new file mode 100644 index 0000000..ed5ab9a Binary files /dev/null and b/testData/classes/pkg/TestAmbiguousCall.class differ diff --git a/testData/classes/pkg/TestAmbiguousCallWithDebugInfo.class b/testData/classes/pkg/TestAmbiguousCallWithDebugInfo.class new file mode 100644 index 0000000..5843a61 Binary files /dev/null and b/testData/classes/pkg/TestAmbiguousCallWithDebugInfo.class differ diff --git a/testData/results/TestAmbiguousCall.dec b/testData/results/TestAmbiguousCall.dec new file mode 100644 index 0000000..b335867 --- /dev/null +++ b/testData/results/TestAmbiguousCall.dec @@ -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"); + } +} diff --git a/testData/results/TestAmbiguousCallWithDebugInfo.dec b/testData/results/TestAmbiguousCallWithDebugInfo.dec new file mode 100644 index 0000000..da3baa9 --- /dev/null +++ b/testData/results/TestAmbiguousCallWithDebugInfo.dec @@ -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"); + } +} diff --git a/testData/results/TestEnum.dec b/testData/results/TestEnum.dec index b32a3d9..3184741 100644 --- a/testData/results/TestEnum.dec +++ b/testData/results/TestEnum.dec @@ -18,7 +18,7 @@ public enum TestEnum { } private TestEnum() { - this((String)"?"); + this("?"); } private TestEnum(@Deprecated String var3) { diff --git a/testData/src/pkg/TestAmbiguousCall.java b/testData/src/pkg/TestAmbiguousCall.java new file mode 100644 index 0000000..0189329 --- /dev/null +++ b/testData/src/pkg/TestAmbiguousCall.java @@ -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"); + } +}