Update jdt.core to I20141029-2000 for Mars M3
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
index 5321ace..12d01da 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
@@ -3115,6 +3115,75 @@
},
customOptions);
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448112, [compiler] Compiler crash (ArrayIndexOutOfBoundsException at StackMapFrame.addStackItem()) with unused variable
+public void test448112() throws Exception {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7)
+ return;
+ Map customOptions = getCompilerOptions();
+ customOptions.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT);
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "\n" +
+ " static class Y {\n" +
+ " public Object getAttribute(String name) {\n" +
+ " return new Long(100L);\n" +
+ " }\n" +
+ " }\n" +
+ " public static void foo2(Y y) {\n" +
+ "\n" +
+ " try {\n" +
+ " long v1 = (Long) y.getAttribute(\"v1\");\n" +
+ " long v2 = (Long) y.getAttribute(\"v2\");\n" +
+ "\n" +
+ " System.out.println(String.valueOf(v1));\n" +
+ "\n" +
+ " } catch (java.lang.Throwable t) {}\n" +
+ " }\n" +
+ " \n" +
+ " public static void main(String args[]) {\n" +
+ " foo2(new Y());\n" +
+ " }\n" +
+ "}",
+ },
+ "100", customOptions);
+ ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
+ byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(new File(OUTPUT_DIR + File.separator +"X.class"));
+ String actualOutput =
+ disassembler.disassemble(
+ classFileBytes,
+ "\n",
+ ClassFileBytesDisassembler.DETAILED);
+
+ String expectedOutput =
+ " public static void foo2(X.Y y);\n" +
+ " 0 aload_0 [y]\n" +
+ " 1 ldc <String \"v1\"> [16]\n" +
+ " 3 invokevirtual X$Y.getAttribute(java.lang.String) : java.lang.Object [18]\n" +
+ " 6 checkcast java.lang.Long [24]\n" +
+ " 9 invokevirtual java.lang.Long.longValue() : long [26]\n" +
+ " 12 lstore_1 [v1]\n" +
+ " 13 aload_0 [y]\n" +
+ " 14 ldc <String \"v2\"> [30]\n" +
+ " 16 invokevirtual X$Y.getAttribute(java.lang.String) : java.lang.Object [18]\n" +
+ " 19 checkcast java.lang.Long [24]\n" +
+ " 22 pop\n" +
+ " 23 getstatic java.lang.System.out : java.io.PrintStream [32]\n" +
+ " 26 lload_1 [v1]\n" +
+ " 27 invokestatic java.lang.String.valueOf(long) : java.lang.String [38]\n" +
+ " 30 invokevirtual java.io.PrintStream.println(java.lang.String) : void [44]\n" +
+ " 33 goto 37\n" +
+ " 36 pop\n" +
+ " 37 return\n";
+ int index = actualOutput.indexOf(expectedOutput);
+ if (index == -1 || expectedOutput.length() == 0) {
+ System.out.println(Util.displayString(actualOutput, 2));
+ }
+ if (index == -1) {
+ assertEquals("Wrong contents", expectedOutput, actualOutput);
+ }
+}
public static Class testClass() {
return CastTest.class;
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
index ab233ba..0e1225e 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
@@ -2553,13 +2553,8 @@
" K extends EntityKey<I>> {\n" +
" }\n" +
"}\n";
- if (this.complianceLevel < ClassFileConstants.JDK1_8) {
- this.runConformTest(
- new String[] { "X.java", source },
- "");
- } else {
- // see https://bugs.eclipse.org/425031
- runNegativeTest(
+
+ runNegativeTest(
new String[] { "X.java", source },
"----------\n" +
"1. WARNING in X.java (at line 3)\n" +
@@ -2567,12 +2562,11 @@
" ^^^^^^^^^\n" +
"X.EntityKey is a raw type. References to generic type X.EntityKey<I> should be parameterized\n" +
"----------\n" +
- "2. ERROR in X.java (at line 4)\n" +
+ "2. WARNING in X.java (at line 4)\n" +
" new EntityCondenser().condense(entityKey); \n" +
- " ^^^^^^^^\n" +
- "The method condense(K) in the type X.EntityCondenser is not applicable for the arguments (X.EntityKey)\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: Unchecked invocation condense(X.EntityKey) of the generic method condense(K) of type X.EntityCondenser\n" +
"----------\n");
- }
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=347600
public void test347600() {
@@ -4577,60 +4571,62 @@
" }\n" +
"\n" +
"}\n";
- if (this.complianceLevel < ClassFileConstants.JDK1_8) {
- runConformTest(
- new String[] {
- "X.java",
- source
- });
- } else {
runNegativeTest(
new String[] {
"X.java",
source
},
"----------\n" +
- "1. ERROR in X.java (at line 8)\n" +
+ "1. WARNING in X.java (at line 8)\n" +
" doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" +
- " ^^^^^^^^^^^^^^^^^^\n" +
- "The method doSomethingWithFoo(X.Foo<T>, X.Foo<T>) in the type X is not applicable for the arguments (X.Foo, X.Foo)\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: Unchecked invocation doSomethingWithFoo(X.Foo, X.Foo) of the generic method doSomethingWithFoo(X.Foo<T>, X.Foo<T>) of type X\n" +
"----------\n" +
- "2. WARNING in X.java (at line 12)\n" +
+ "2. WARNING in X.java (at line 8)\n" +
+ " doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" +
+ "----------\n" +
+ "3. WARNING in X.java (at line 8)\n" +
+ " doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" +
+ "----------\n" +
+ "4. WARNING in X.java (at line 12)\n" +
" Foo foo = any( Foo.class );\n" +
" ^^^\n" +
"X.Foo is a raw type. References to generic type X.Foo<T> should be parameterized\n" +
"----------\n" +
- "3. WARNING in X.java (at line 13)\n" +
+ "5. WARNING in X.java (at line 13)\n" +
" doSomethingWithFoo( foo, foo );\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Type safety: Unchecked invocation doSomethingWithFoo(X.Foo, X.Foo) of the generic method doSomethingWithFoo(X.Foo<T>, X.Foo<T>) of type X\n" +
"----------\n" +
- "4. WARNING in X.java (at line 13)\n" +
+ "6. WARNING in X.java (at line 13)\n" +
" doSomethingWithFoo( foo, foo );\n" +
" ^^^\n" +
"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" +
"----------\n" +
- "5. WARNING in X.java (at line 13)\n" +
+ "7. WARNING in X.java (at line 13)\n" +
" doSomethingWithFoo( foo, foo );\n" +
" ^^^\n" +
"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" +
"----------\n" +
- "6. WARNING in X.java (at line 17)\n" +
+ "8. WARNING in X.java (at line 17)\n" +
" this.<Object>doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Type safety: Unchecked invocation doSomethingWithFoo(X.Foo, X.Foo) of the generic method doSomethingWithFoo(X.Foo<T>, X.Foo<T>) of type X\n" +
"----------\n" +
- "7. WARNING in X.java (at line 17)\n" +
+ "9. WARNING in X.java (at line 17)\n" +
" this.<Object>doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" +
" ^^^^^^^^^^^^^^^^\n" +
"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" +
"----------\n" +
- "8. WARNING in X.java (at line 17)\n" +
+ "10. WARNING in X.java (at line 17)\n" +
" this.<Object>doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" +
" ^^^^^^^^^^^^^^^^\n" +
"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" +
"----------\n");
- }
}
public void _testBug430686() {
runConformTest(
@@ -5471,7 +5467,6 @@
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=440019, [1.8][compiler] Type mismatch error with autoboxing/scalar types (works with 1.6)
public void test440019() {
- if (this.complianceLevel <= ClassFileConstants.JDK1_7)
this.runConformTest(
new String[] {
"A.java",
@@ -5486,9 +5481,8 @@
"");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=443596, [1.8][compiler] Failure for overload resolution in case of Generics and Varags
-public void _test443596() {
- if (this.complianceLevel >= ClassFileConstants.JDK1_7)
- this.runNegativeTest(
+public void test443596() {
+ this.runNegativeTest(
new String[] {
"X.java",
"public final class X {\n" +
@@ -5502,6 +5496,8 @@
" }\n" +
"}\n",
},
+ this.complianceLevel < ClassFileConstants.JDK1_7 ?
+ "" :
"----------\n" +
"1. WARNING in X.java (at line 4)\n" +
" public static <T> Predicate<T> and(Predicate<? super T>... arg) { return null; }\n" +
@@ -5509,5 +5505,261 @@
"Type safety: Potential heap pollution via varargs parameter arg\n" +
"----------\n");
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=446235, Java8 generics and boxing
+public void test446235() {
+ this.runConformTest(
+ new String[] {
+ "IntegerLongBug.java",
+ "public class IntegerLongBug {\n" +
+ " public static void main(String ar[]) {\n" +
+ " Integer number = 1000;\n" +
+ " long numberLong = number; //compiles fine\n" +
+ " long num = getNumber(5000); // compilation error\n" +
+ " }\n" +
+ " public static <T> T getNumber(T num) {\n" +
+ " return num;\n" +
+ " }\n" +
+ "}\n",
+ },
+ "");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=440019, [1.8][compiler] Type mismatch error with autoboxing/scalar types (works with 1.6)
+public void test440019_c9() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static final int CORE_POOL_SIZE = 3;\n" +
+ " public static final int KEEP_ALIVE_TIME = 60; // seconds\n" +
+ " X(final int size, final long ttl){\n" +
+ " System.out.println(\"size: \" + size + \" \" + \" ttl: \" + ttl);\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " new X(CORE_POOL_SIZE, get(KEEP_ALIVE_TIME)); // [1]\n" +
+ " }\n" +
+ " public static <T> T get(T value) {\n" +
+ " return value;\n" +
+ " }\n" +
+ "}\n",
+ },
+ "size: 3 ttl: 60");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=446223, [1.8][compiler] Java8 generics eclipse doesn't compile
+public void test446223() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String ar[]) {\n" +
+ " System.out.println(\"hi\");\n" +
+ " DoNothing();\n" +
+ " }\n" +
+ " public interface Interface1 {\n" +
+ " public void go();\n" +
+ " }\n" +
+ " public interface Interface2<X> {\n" +
+ " public X go2();\n" +
+ " }\n" +
+ " private static <X, T extends Interface2<X> & Interface1> void DoNothing() {\n" +
+ " return;\n" +
+ " }\n" +
+ "}\n",
+ },
+ "----------\n" +
+ "1. WARNING in X.java (at line 9)\n" +
+ " public interface Interface2<X> {\n" +
+ " ^\n" +
+ "The type parameter X is hiding the type X\n" +
+ "----------\n" +
+ "2. WARNING in X.java (at line 12)\n" +
+ " private static <X, T extends Interface2<X> & Interface1> void DoNothing() {\n" +
+ " ^\n" +
+ "The type parameter X is hiding the type X\n" +
+ "----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=444334, [1.8][compiler] Compiler generates error instead of warning on unchecked conversion
+public void test444334() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.ArrayList;\n" +
+ "import java.util.List;\n" +
+ "public class X {\n" +
+ " public static void Main(String[] args) {\n" +
+ " doSomething(returnClassType(Class.class));\n" +
+ " doSomething(returnListType(new ArrayList<List>()));\n" +
+ " }\n" +
+ " public static <T> void doSomething(Class<T> clazz) {\n" +
+ " System.out.println(clazz.getSimpleName());\n" +
+ " }\n" +
+ " public static <T> T returnClassType(Class<T> clazz) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static <T> void doSomething(List<T> list) {\n" +
+ " System.out.println(list.getClass().getSimpleName());\n" +
+ " }\n" +
+ " public static <T> T returnListType(List<T> list) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n",
+ },
+ "----------\n" +
+ "1. WARNING in X.java (at line 5)\n" +
+ " doSomething(returnClassType(Class.class));\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: Unchecked invocation doSomething(Class) of the generic method doSomething(Class<T>) of type X\n" +
+ "----------\n" +
+ "2. WARNING in X.java (at line 5)\n" +
+ " doSomething(returnClassType(Class.class));\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: The expression of type Class needs unchecked conversion to conform to Class<Object>\n" +
+ "----------\n" +
+ "3. WARNING in X.java (at line 6)\n" +
+ " doSomething(returnListType(new ArrayList<List>()));\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: Unchecked invocation doSomething(List) of the generic method doSomething(List<T>) of type X\n" +
+ "----------\n" +
+ "4. WARNING in X.java (at line 6)\n" +
+ " doSomething(returnListType(new ArrayList<List>()));\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: The expression of type List needs unchecked conversion to conform to List<Object>\n" +
+ "----------\n" +
+ "5. WARNING in X.java (at line 6)\n" +
+ " doSomething(returnListType(new ArrayList<List>()));\n" +
+ " ^^^^\n" +
+ "List is a raw type. References to generic type List<E> should be parameterized\n" +
+ "----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=438246, [1.8][compiler] Java 8 static methods compilation error
+public void test438246() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_7)
+ return;
+ this.runNegativeTest(
+ new String[] {
+ "Foo.java",
+ "import java.util.List;\n" +
+ "public abstract class Foo<C>\n" +
+ "{\n" +
+ " @SuppressWarnings(\"unchecked\")\n" +
+ " public static <C> void doit( List<Foo<C>> workers )\n" +
+ " {\n" +
+ " doit( workers.toArray( new Foo[workers.size()] ) );\n" +
+ " }\n" +
+ " public static <C> void doit( Foo<C>... workers )\n" +
+ " {\n" +
+ " }\n" +
+ "}\n",
+ },
+ "----------\n" +
+ "1. WARNING in Foo.java (at line 9)\n" +
+ " public static <C> void doit( Foo<C>... workers )\n" +
+ " ^^^^^^^\n" +
+ "Type safety: Potential heap pollution via varargs parameter workers\n" +
+ "----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448795, [1.8][compiler] Inference should discriminate between strict and loose modes
+public void test448795() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X<T> {\n" +
+ " static <T> T element(T [] ta) {\n" +
+ " return ta[0];\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " int x = element(new int [] { 1234 });\n" + // check that autoboxing does not kick in for arrays, i.e engine should not slip into loose mode.
+ " }\n" +
+ "}\n",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " int x = element(new int [] { 1234 });\n" +
+ " ^^^^^^^\n" +
+ "The method element(T[]) in the type X<T> is not applicable for the arguments (int[])\n" +
+ "----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448795, [1.8][compiler] Inference should discriminate between strict and loose modes
+public void test448795a() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X<T> {\n" +
+ " static <T> T element(int x, T t) {\n" +
+ " System.out.println(\"Strict\");\n" +
+ " return t;\n" +
+ " }\n" +
+ " static <T> T element(T t1, T t2) {\n" +
+ " System.out.println(\"Loose\");\n" +
+ " return t2;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " int x = element(10, new Integer(20));\n" +
+ " }\n" +
+ "}\n",
+ },
+ "Strict");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448795, [1.8][compiler] Inference should discriminate between strict and loose modes
+public void test448795b() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X<T> {\n" +
+ " static int element(int x, Integer t) {\n" +
+ " System.out.println(\"non-generic\");\n" +
+ " return t;\n" +
+ " }\n" +
+ " static <T> T element(int t1, T t2) {\n" +
+ " System.out.println(\"generic\");\n" +
+ " return t2;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " int x = element(10, new Integer(20));\n" +
+ " }\n" +
+ "}\n",
+ },
+ "non-generic");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448795, [1.8][compiler] Inference should discriminate between strict and loose modes
+public void test448795c() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X<T> {\n" +
+ " static int element(Integer x, Integer t) {\n" +
+ " System.out.println(\"non-generic\");\n" +
+ " return t;\n" +
+ " }\n" +
+ " static <T> T element(int t1, T t2) {\n" +
+ " System.out.println(\"generic\");\n" +
+ " return t2;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " int x = element(10, new Integer(20));\n" +
+ " }\n" +
+ "}\n",
+ },
+ "generic");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=434118, [1.8][compiler] Compilation error on generic capture/type inference
+public void test434118() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public Object convertFails(Class<?> clazz, String value) {\n" +
+ " return Enum.valueOf(clazz.asSubclass(Enum.class), value);\n" +
+ " }\n" +
+ " public Object convertCompiles(Class<?> clazz, String value) {\n" +
+ " return Enum.valueOf(clazz.<Enum>asSubclass(Enum.class), value);\n" +
+ " }\n" +
+ " public Object convertCompiles2(Class<?> clazz, String value) {\n" +
+ " Class<? extends Enum> enumType = clazz.asSubclass(Enum.class);\n" +
+ " return Enum.valueOf(enumType, value);\n" +
+ " }\n" +
+ "}\n",
+ },
+ "");
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_7.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_7.java
index be9a8bf..dbc14e9 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_7.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_7.java
@@ -2677,6 +2677,85 @@
},
"Expected CCE");
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448028, [1.8] 1.8 cannot infer type arguments where 1.7 does
+public void test448028() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(CompilerOptions.OPTION_ReportRedundantSpecificationOfTypeArguments, CompilerOptions.ERROR);
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "\n" +
+ " public static interface I {/*empty*/}\n" +
+ "\n" +
+ " public static class C\n" +
+ " implements I {/*empty*/}\n" +
+ "\n" +
+ " public static class W<T extends I>\n" +
+ " implements I {\n" +
+ "\n" +
+ " // --- problem is triggered only, when there is a vararg-parameter\n" +
+ " public W(final T t, final Object... o) {\n" +
+ " super();\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " // --- needed to trigger problem\n" +
+ " public static final <T> T inspect(final T t) {\n" +
+ " return t;\n" +
+ " }\n" +
+ "\n" +
+ " // --- this compiles ok when having JDK Compilance set to 1.7 !\n" +
+ " public static final W<C> err1() {\n" +
+ " final C c = new C();\n" +
+ " final Object o = new Object();\n" +
+ " return inspect(new W<>(c, o)); // - ERROR: Cannot infer type arguments for W<> F.java\n" +
+ " }\n" +
+ "\n" +
+ " public static final W<C> wrn1() {\n" +
+ " final C c = new C();\n" +
+ " final Object o = new Object();\n" +
+ " // --- giving the type-parameter yields a warning\n" +
+ " // --- comparing that to the error of method err1() it does not make much sense\n" +
+ " return inspect(new W<C>(c, o)); // - WARNING: Redundant specification of type arguments <F.C> F.java\n" +
+ " }\n" +
+ "\n" +
+ " public static final W<C> ok1() {\n" +
+ " final C c = new C();\n" +
+ " // --- no extra vararg-paramaeter\n" +
+ " return inspect(new W<>(c)); // - OK\n" +
+ " }\n" +
+ "\n" +
+ " public static final W<C> ok2() {\n" +
+ " final C c = new C();\n" +
+ " final Object o = new Object();\n" +
+ " // --- no check-method\n" +
+ " return new W<>(c, o); // - OK\n" +
+ " }\n" +
+ "\n" +
+ " public static final W<C> ok3() {\n" +
+ " final C c = new C();\n" +
+ " // --- no check-method\n" +
+ " return new W<>(c); // - OK\n" +
+ " }\n" +
+ "\n" +
+ " public static final W<C> ok4() {\n" +
+ " final C c = new C();\n" +
+ " final Object o = new Object();\n" +
+ " // --- this also compiles (my solution for now)\n" +
+ " final W<C> w = new W<>(c, o);\n" +
+ " return inspect(w);\n" +
+ " }\n" +
+ "}\n",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 34)\n" +
+ " return inspect(new W<C>(c, o)); // - WARNING: Redundant specification of type arguments <F.C> F.java\n" +
+ " ^\n" +
+ "Redundant specification of type arguments <X.C>\n" +
+ "----------\n",
+ null, false, customOptions);
+}
public static Class testClass() {
return GenericsRegressionTest_1_7.class;
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
index 02b2ffd..86a9f90 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
@@ -4680,4 +4680,116 @@
},
"");
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=434394, [1.8] inference fails in some cases when conditional expression is involved
+public void test434394() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "import java.util.ArrayList;\n" +
+ "import java.util.Collections;\n" +
+ "import java.util.Comparator;\n" +
+ "import java.util.List;\n" +
+ "public class X {\n" +
+ " public void bla() {\n" +
+ " boolean b = Boolean.TRUE.booleanValue();\n" +
+ " List<String> c1 = new ArrayList<>();\n" +
+ " Collections.sort(c1, new Foo(new State<>((b ? new Val<>(\"AAAA\") : new Val<>(\"BBBB\"))))); // Cannot infer type arguments for State\n" +
+ " Collections.sort(c1,new Foo(b ? new State<>(new Val<>(\"AAAA\")) : new State<>(new Val<>(\"BBBB\")))); // this is fine\n" +
+ " }\n" +
+ " static class Foo implements Comparator<String>{\n" +
+ " public Foo(State<String> st) {\n" +
+ " //\n" +
+ " }\n" +
+ " @Override\n" +
+ " public int compare(String o1, String o2) {\n" +
+ " // TODO Auto-generated method stub\n" +
+ " return 0;\n" +
+ " }\n" +
+ " }\n" +
+ " static class State<R> {\n" +
+ " State(Val<?> o) {\n" +
+ " }\n" +
+ " }\n" +
+ " static class Val<T> {\n" +
+ " Val(T t) {}\n" +
+ " }\n" +
+ "}\n",
+ },
+ "");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=445725, [1.8][inference] Type inference not occurring with lambda expression and constructor reference
+public void test445725() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "import java.util.ArrayList;\n" +
+ "import java.util.Arrays;\n" +
+ "import java.util.Collection;\n" +
+ "import java.util.function.Function;\n" +
+ "import java.util.stream.Collectors;\n" +
+ "import java.util.stream.Stream;\n" +
+ "public class X {\n" +
+ "/**\n" +
+ " * Takes a collection, applies a mapper to it, and then passes the result into the finishing\n" +
+ " * function\n" +
+ " */\n" +
+ " public static <FROM, TO, RESULT> RESULT mapped(Collection<FROM> collection,\n" +
+ " Function<? super FROM, ? extends TO> mapper,\n" +
+ " Function<? super Collection<TO>, RESULT> finisher)\n" +
+ " {\n" +
+ " return mapped(collection.stream(), mapper, finisher);\n" +
+ " }\n" +
+ " /**\n" +
+ " * Takes a stream, applies a mapper to it, and then passes the result into the finishing function\n" +
+ " */\n" +
+ " public static <FROM, TO, RESULT> RESULT mapped(Stream<FROM> stream,\n" +
+ " Function<? super FROM, ? extends TO> mapper,\n" +
+ " Function<? super Collection<TO>, RESULT> finisher)\n" +
+ " {\n" +
+ " return finisher.apply(stream.map(mapper).collect(Collectors.toList()));\n" +
+ " }\n" +
+ " public static void example()\n" +
+ " {\n" +
+ " mapped(Stream.of(\"1, 2, 3\"), Integer::parseInt, ArrayList<Integer>::new);\n" +
+ " mapped(Arrays.asList(\"1, 2, 3\"), Integer::parseInt, ArrayList<Integer>::new);\n" +
+ "\n" +
+ " mapped(Stream.of(\"1, 2, 3\"), Integer::parseInt, IntCollection::new);\n" +
+ " mapped(Arrays.asList(\"1, 2, 3\"), Integer::parseInt, IntCollection::new);\n" +
+ " }\n" +
+ " public static class IntCollection extends ArrayList<Integer>\n" +
+ " {\n" +
+ " public IntCollection(Collection<Integer> numbers)\n" +
+ " {\n" +
+ " super(numbers);\n" +
+ " }\n" +
+ " }\n" +
+ "}\n",
+ },
+ "");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
+public void test447767() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "interface I {\n" +
+ " void bar(String t);\n" +
+ "}\n" +
+ "public class X<T> {\n" +
+ " X(String x) {}\n" +
+ " X(T x) { \n" +
+ " System.out.println(\"Here\");\n" +
+ " }\n" +
+ " X(T x, String ...strings) {}\n" +
+ " public void one(X<I> c){}\n" +
+ " public void two() {\n" +
+ " one(new X<>((String s) -> { }));\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " new X(\"\").two();\n" +
+ " }\n" +
+ "}\n",
+ },
+ "Here");
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
index b289c37..9623df9 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
@@ -149,7 +149,189 @@
"}"
});
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448724, [1.8] [compiler] Wrong resolution of overloaded method when irrelevant type parameter is present and lambda is used as parameter
+public void test448724() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "import java.util.concurrent.Callable;\n" +
+ "public class X {\n" +
+ " public void mismatchRunnableCallable() throws Exception {\n" +
+ " //Resolves to case1(Runnable) method invocation; lambda with block\n" +
+ " case1(() -> {\"abc\".length();});\n" +
+ " //Resolves to case1(Callable) method invocation, resulting in type mismatch; block removed - lambda with expression\n" +
+ " case1(() -> \"abc\".length());\n" +
+ " }\n" +
+ " public void noSuchMismatch() throws Exception {\n" +
+ " //no difference to case1 \n" +
+ " case2(() -> {\"abc\".length();});\n" +
+ " //the only difference to case 1 is the missing irrelevant <T> type parameter. Properly resolves to case2(Runnable) here\n" +
+ " case2(() -> \"abc\".length());\n" +
+ " }\n" +
+ " public void case1(final Runnable r) {\n" +
+ " System.out.println(\"case1: Runnable\");\n" +
+ " }\n" +
+ " public <T> void case1(Callable<Boolean> c) {\n" +
+ " System.out.println(\"case1: Callable\");\n" +
+ " }\n" +
+ " public void case2(final Runnable supplier) {\n" +
+ " System.out.println(\"case2: Runnable\");\n" +
+ " }\n" +
+ " public void case2(Callable<Boolean> conditionEvaluator) {\n" +
+ " System.out.println(\"case2: Callable\");\n" +
+ " }\n" +
+ " public static void main(String[] args) throws Exception {\n" +
+ " new X().mismatchRunnableCallable();\n" +
+ " new X().noSuchMismatch();\n" +
+ " }\n" +
+ "}\n"
+ },
+ "case1: Runnable\n" +
+ "case1: Runnable\n" +
+ "case2: Runnable\n" +
+ "case2: Runnable");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
+public void test447767() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "interface I<T, U, V> {\n" +
+ " T goo(U u, V v);\n" +
+ "}\n" +
+ "public class X {\n" +
+ " static <T, U, V> T foo(T t, U u, V v) {\n" +
+ " System.out.println(\"Wrong!\");\n" +
+ " return null;\n" +
+ " }\n" +
+ " static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
+ " System.out.println(\"Right!\");\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" +
+ " }\n" +
+ " static <T> T goo(T t) {\n" +
+ " return t; \n" +
+ " }\n" +
+ "}\n"
+ },
+ "Right!");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
+public void test447767a() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "interface I<T, U, V> {\n" +
+ " T goo(U u, V v);\n" +
+ "}\n" +
+ "public class X {\n" +
+ " static <T, U, V> T foo(T t, U u, I<T, U, V> i) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" +
+ " }\n" +
+ " static <T> T goo(T t) {\n" +
+ " return t; \n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 9)\n" +
+ " String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" +
+ " ^\n" +
+ "Type mismatch: cannot convert from Object to String\n" +
+ "----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
+public void test447767b() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "interface I<T, U, V> {\n" +
+ " T goo(U u, V v);\n" +
+ "}\n" +
+ "public class X {\n" +
+ " static String goo(String s, String s2) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
+ " System.out.println(\"Right!\");\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " String s = goo(foo(\"String\", \"String\", X::goo));\n" +
+ " }\n" +
+ " static <T> T goo(T t) {\n" +
+ " return t; \n" +
+ " }\n" +
+ "}\n"
+ },
+ "Right!");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
+public void test447767c() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "interface I<T, U, V> {\n" +
+ " T goo(U u, V v);\n" +
+ "}\n" +
+ "public class X {\n" +
+ " static String goo(String s, String s2) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " static <T, U, V> T foo(T t, U u, V v) {\n" +
+ " System.out.println(\"Wrong!\");\n" +
+ " return null;\n" +
+ " }\n" +
+ " static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
+ " System.out.println(\"Right!\");\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " String s = goo(foo(\"String\", \"String\", X::goo));\n" +
+ " }\n" +
+ " static <T> T goo(T t) {\n" +
+ " return t; \n" +
+ " }\n" +
+ "}\n"
+ },
+ "Right!");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
+public void test447767d() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "interface I<T, U, V> {\n" +
+ " T goo(U u, V v);\n" +
+ "}\n" +
+ "public class X {\n" +
+ " static String goo(String s, String s2) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " static <T, U, V> T foo(T t, U u, V v) {\n" +
+ " System.out.println(\"Wrong!\");\n" +
+ " return null;\n" +
+ " }\n" +
+ " static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
+ " System.out.println(\"Right!\");\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " String s = goo(foo(\"String\", \"String\", X::goo));\n" +
+ " }\n" +
+ " static <T> T goo(T t) {\n" +
+ " return t; \n" +
+ " }\n" +
+ "}\n"
+ },
+ "Right!");
+}
public static Class testClass() {
return LambdaRegressionTest.class;
}
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
index ead8f60..0800e28 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
@@ -8482,7 +8482,7 @@
"");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=428177, - [1.8][compiler] Insistent capture issues
-public void _test428177() {
+public void test428177() {
runNegativeTest(
new String[] {
"X.java",
@@ -8533,7 +8533,32 @@
" }\n" +
"}\n"
},
- "valid error messages go here - some are expected since javac also complains");
+ "----------\n" +
+ "1. ERROR in X.java (at line 19)\n" +
+ " Stream<String> stream2 = entries.map(toName).distinct(); // ERROR\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type mismatch: cannot convert from Stream<capture#7-of ? extends String> to Stream<String>\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 20)\n" +
+ " withoutWildcard(entries.map(toName).distinct()); // ERROR\n" +
+ " ^^^^^^^^^^^^^^^\n" +
+ "The method withoutWildcard(Stream<String>) in the type InsistentCapture is not applicable for the arguments (Stream<capture#9-of ? extends String>)\n" +
+ "----------\n" +
+ "3. ERROR in X.java (at line 21)\n" +
+ " withoutWildcard(stream); // ERROR\n" +
+ " ^^^^^^^^^^^^^^^\n" +
+ "The method withoutWildcard(Stream<String>) in the type InsistentCapture is not applicable for the arguments (Stream<capture#10-of ? extends String>)\n" +
+ "----------\n" +
+ "4. ERROR in X.java (at line 36)\n" +
+ " if(\"1\" == \"\") { return stream.collect(Collectors.toList()).stream(); // ERROR\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type mismatch: cannot convert from Stream<capture#14-of ? extends String> to Stream<String>\n" +
+ "----------\n" +
+ "5. ERROR in X.java (at line 38)\n" +
+ " return stream.collect(Collectors.toList()); // NO ERROR\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type mismatch: cannot convert from List<capture#19-of ? extends String> to Stream<String>\n" +
+ "----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=428795, - [1.8]Internal compiler error: java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.ast.MessageSend.analyseCode
public void test428795() {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
index f14cfec..afd507b 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
@@ -81,6 +81,7 @@
import org.eclipse.jdt.internal.core.search.indexing.IndexRequest;
import org.eclipse.jdt.internal.core.search.matching.AndPattern;
import org.eclipse.jdt.internal.core.search.matching.MatchLocator;
+import org.eclipse.jdt.internal.core.search.matching.MethodPattern;
import org.eclipse.jdt.internal.core.search.matching.PatternLocator;
import org.eclipse.jdt.internal.core.search.matching.TypeDeclarationPattern;
@@ -13434,5 +13435,805 @@
"src/b400919/X.java b400919.X2 [Marker] EXACT_MATCH"
);
}
-// Add new tests in JavaSearchBugsTests2
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_001() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface I { \n" +
+ " public void query(Foo.InnerKey key);// Search result of method query(Foo.InnerKey) returns the method query(Bar.InnerKey) too \n" +
+ " public void query(Bar.InnerKey key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey {}\n" +
+ "}\n" +
+ "class Bar {\n" +
+ " static class InnerKey {}\n" +
+ "}\n" +
+ "\n" +
+ "class X {\n" +
+ " public static void foo(I i, Foo.InnerKey key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " public static void bar(I i, Bar.InnerKey key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " public static I getInstance() {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query";
+ int start = str.indexOf(selection);
+ int length = selection.length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], REFERENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(
+ "src/X.java void X.foo(I, Foo.InnerKey) [query(key)] EXACT_MATCH"
+ );
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_002() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface I { \n" +
+ " public void query(Foo.InnerKey key);// Search result of method query(Foo.InnerKey) returns the method query(Bar.InnerKey) too \n" +
+ " public void query(Bar.InnerKey key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey {}\n" +
+ "}\n" +
+ "class Bar {\n" +
+ " static class InnerKey {}\n" +
+ "}\n" +
+ "\n" +
+ "class X {\n" +
+ " public static void foo(I i, Foo.InnerKey key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " public static void bar(I i, Bar.InnerKey key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " public static I getInstance() {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query";
+ int start = str.indexOf(selection);
+ int length = selection.length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults( "src/X.java void I.query(Foo.InnerKey) [query] EXACT_MATCH\n" +
+ "src/X.java void X.foo(I, Foo.InnerKey) [query(key)] EXACT_MATCH"
+ );
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_003() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface I { \n" +
+ " public void query(Foo.InnerKey key);// Search result of method query(Foo.InnerKey) returns the method query(Bar.InnerKey) too \n" +
+ " public void query/*here*/(Bar.InnerKey key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey {}\n" +
+ "}\n" +
+ "class Bar {\n" +
+ " static class InnerKey {}\n" +
+ "}\n" +
+ "\n" +
+ "class X {\n" +
+ " public static void foo(I i, Foo.InnerKey key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " public static void bar(I i, Bar.InnerKey key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " public static I getInstance() {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults("src/X.java void I.query(Bar.InnerKey) [query] EXACT_MATCH\n" +
+ "src/X.java void X.bar(I, Bar.InnerKey) [query(key)] EXACT_MATCH"
+ );
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_004() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "// --\n" +
+ "interface I { \n" +
+ " public void query/*here*/(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+ " public void query(Key key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class Key { \n" +
+ " }\n" +
+ " public static void foo(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Key {\n" +
+ " \n" +
+ "}\n" +
+ "class Bar {\n" +
+ " \n" +
+ " public static void bar(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "public class X {\n" +
+ " public static I getInstance() {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(
+ "src/X.java void I.query(Foo.Key) [query] EXACT_MATCH\n" +
+ "src/X.java void Foo.foo(I, Key) [query(key)] EXACT_MATCH"
+ );
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_005() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "// --\n" +
+ "interface I { \n" +
+ " public void query(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+ " public void query/*here*/(Key key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class Key { \n" +
+ " }\n" +
+ " public static void foo(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Key {\n" +
+ " \n" +
+ "}\n" +
+ "class Bar {\n" +
+ " \n" +
+ " public static void bar(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "public class X {\n" +
+ " public static I getInstance() {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(
+ "src/X.java void I.query(Key) [query] EXACT_MATCH\n" +
+ "src/X.java void Bar.bar(I, Key) [query(key)] EXACT_MATCH"
+ );
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_006() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "// --\n" +
+ "interface I { \n" +
+ " public void query/*here*/(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+ " public void query(Key key);\n" +
+ " public void query(Bar.Key key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class Key { \n" +
+ " }\n" +
+ " public static void foo(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Key {\n" +
+ " \n" +
+ "}\n" +
+ "class Bar {\n" +
+ " static class Key {\n" +
+ " \n" +
+ " } \n" +
+ " public static void bar(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "public class X {\n" +
+ " public static I getInstance() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static void bar(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ "}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(
+ "src/X.java void I.query(Foo.Key) [query] EXACT_MATCH\n" +
+ "src/X.java void Foo.foo(I, Key) [query(key)] EXACT_MATCH"
+ );
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_007() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "// --\n" +
+ "interface I { \n" +
+ " public void query(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+ " public void query/*here*/(Key key);\n" +
+ " public void query(Bar.Key key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class Key { \n" +
+ " }\n" +
+ " public static void foo(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Key {\n" +
+ " \n" +
+ "}\n" +
+ "class Bar {\n" +
+ " static class Key {\n" +
+ " \n" +
+ " } \n" +
+ " public static void bar(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "public class X {\n" +
+ " public static I getInstance() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static void bar(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ "}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(
+ "src/X.java void I.query(Key) [query] EXACT_MATCH\n" +
+ "src/X.java void X.bar(I, Key) [query(key)] EXACT_MATCH"
+ );
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_008() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "// --\n" +
+ "interface I { \n" +
+ " public void query(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+ " public void query(Key key);\n" +
+ " public void query/*here*/(Bar.Key key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class Key { \n" +
+ " }\n" +
+ " public static void foo(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Key {\n" +
+ " \n" +
+ "}\n" +
+ "class Bar {\n" +
+ " static class Key {\n" +
+ " \n" +
+ " } \n" +
+ " public static void bar(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "public class X {\n" +
+ " public static I getInstance() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static void bar(I i, Key key) {\n" +
+ " i.query(key);\n" +
+ " }\n" +
+ "}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(
+ "src/X.java void I.query(Bar.Key) [query] EXACT_MATCH\n" +
+ "src/X.java void Bar.bar(I, Key) [query(key)] EXACT_MATCH"
+ );
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_009() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface MyIF { \n" +
+ " public void query(Foo.InnerKey fk, Bar.InnerKey bk, String s); \n" +
+ " public void query/*here*/(Bar.InnerKey fk, Bar.InnerKey bk, String s);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey { \n" +
+ " }\n" +
+ "\n" +
+ "}\n" +
+ "\n" +
+ "class Bar {\n" +
+ " static class InnerKey {\n" +
+ " }\n" +
+ " public static void bar(MyIF i, Foo.InnerKey fk, Bar.InnerKey bk) {\n" +
+ " i.query(fk, bk, \"\");\n" +
+ " }\n" +
+ "}\n" +
+ "public class X {}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], REFERENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(""
+ );
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_010() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface MyIF { \n" +
+ " public void query(Foo.InnerKey fk, String s); \n" +
+ " public void query/*here*/(Bar.InnerKey fk, String s);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey {}\n" +
+ "}\n" +
+ "\n" +
+ "class Bar {\n" +
+ " static class InnerKey {}\n" +
+ " public static void bar(MyIF i, Foo.InnerKey fk) {\n" +
+ " i.query(fk, \"\");\n" +
+ " }\n" +
+ "}\n" +
+ "public class X {}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], REFERENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(""
+ );
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_011() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface MyIF { \n" +
+ " public void query(String s, Foo.InnerKey fk); \n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey {}\n" +
+ "}\n" +
+ "\n" +
+ "class Bar {\n" +
+ " static class InnerKey {}\n" +
+ " public static void bar(MyIF i, Foo.InnerKey fk) {\n" +
+ " i.query(\"\", fk);\n" +
+ " }\n" +
+ "}\n" +
+ "public class X {}\n"
+ );
+
+ String nonExistentPattern = "MyIF.query(String, Bar.InnerKey)";
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(nonExistentPattern, IJavaSearchConstants.METHOD, REFERENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults(""
+ );
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_012() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface MyIF { \n" +
+ " public void query/*here*/(Foo.InnerKey fk, Bar.InnerKey bk, String s); \n" +
+ " public void query(Bar.InnerKey fk, Bar.InnerKey bk, String s);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey { \n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Bar {\n" +
+ " static class InnerKey extends Foo.InnerKey {\n" +
+ " }\n" +
+ " public static void bar(MyIF i, Foo.InnerKey fk, Bar.InnerKey bk) {\n" +
+ " i.query(fk, bk, \"\");\n" +
+ " }\n" +
+ "}\n" +
+ "public class X {}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults("src/X.java void MyIF.query(Foo.InnerKey, Bar.InnerKey, String) [query] EXACT_MATCH\n" +
+ "src/X.java void Bar.bar(MyIF, Foo.InnerKey, Bar.InnerKey) [query(fk, bk, \"\")] EXACT_MATCH"
+ );
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_013() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface MyIF { \n" +
+ " public void query/*here*/(Foo.InnerKey key); \n" +
+ " public void query(Bar.InnerKey key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey { \n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Bar {\n" +
+ " static class InnerKey{}\n" +
+ "}\n" +
+ "public class X {}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults("src/X.java void MyIF.query(Foo.InnerKey) [query] EXACT_MATCH"
+ );
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_014() throws CoreException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+ "interface MyIF { \n" +
+ " public void query/*here*/(Foo.InnerKey key); \n" +
+ " public void query(Bar.InnerKey key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey { \n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Bar {\n" +
+ " static class InnerKey{}\n" +
+ "}\n" +
+ "public class X {}\n"
+ );
+
+ String str = this.workingCopies[0].getSource();
+ String selection = "query/*here*/";
+ int start = str.indexOf(selection);
+ int length = "query".length();
+
+ IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+ MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], DECLARATIONS, EXACT_RULE | ERASURE_RULE);
+
+ new SearchEngine(this.workingCopies).search(pattern,
+ new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+ getJavaSearchWorkingCopiesScope(),
+ this.resultCollector,
+ null);
+ assertSearchResults("src/X.java void MyIF.query(Foo.InnerKey) [query] EXACT_MATCH");
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_015() throws CoreException {
+ String folder = "/JavaSearchBugs/src/testBug431357_015";
+ String filename = folder + "/" + "X.java";
+ try {
+ String contents =
+ "package testBug431357_015;\n" +
+ "interface MyIF { \n" +
+ " public void query/*here*/(Foo.InnerKey key); \n" +
+ " public void query(Bar.InnerKey key);\n" +
+ "}\n" +
+ "\n" +
+ "class Foo { \n" +
+ " static class InnerKey { \n" +
+ " }\n" +
+ " \n" +
+ "}\n" +
+ "\n" +
+ "class Bar {\n" +
+ " static class InnerKey{}\n" +
+ "}\n" +
+ "public class X {}\n";
+ // create files
+ createFolder(folder);
+ createFile(filename, contents);
+ waitUntilIndexesReady();
+
+ // search
+ IType[] types = getCompilationUnit(filename).getTypes();
+ IMethod method = types[0].getMethods()[0];
+ search(method, DECLARATIONS | IJavaSearchConstants.IGNORE_DECLARING_TYPE | IJavaSearchConstants.IGNORE_RETURN_TYPE, ERASURE_RULE);
+ assertSearchResults("src/testBug431357_015/X.java void testBug431357_015.MyIF.query(Foo.InnerKey) [query] EXACT_MATCH");
+ }
+ finally {
+ // delete files
+ deleteFolder(folder);
+ }
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * enable this once 88997 is fixed
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void _testBug431357_016() throws CoreException {
+ String folder = "/JavaSearchBugs/src/testBug431357_016";
+ String filename = folder + "/" + "X.java";
+ try {
+ String contents =
+ "package testBug431357_016;\n" +
+ "interface I { \n " +
+ " public void query(Foo.Key key);\n" +
+ " public void query/*here*/(Key key);\n " +
+ "}\n " +
+ "\n " +
+ "class Foo { \n " +
+ " static class Key { \n " +
+ " }\n " +
+ " public static void foo(I i, Key key) {\n " +
+ " i.query(key);\n " +
+ " }\n " +
+ " \n " +
+ "}\n " +
+ "\n " +
+ "class Key {\n " +
+ " \n " +
+ "}\n " +
+ "class Bar {\n " +
+ " \n " +
+ " public static void bar(I i, Key key) {\n " +
+ " i.query(key);\n " +
+ " }\n " +
+ "}\n " +
+ "\n " +
+ "public class X {\n " +
+ " public static I getInstance() {\n " +
+ " return null;\n " +
+ " }\n " +
+ "}\n ";
+ // create files
+ createFolder(folder);
+ createFile(filename, contents);
+ waitUntilIndexesReady();
+
+ // search
+ IType[] types = getCompilationUnit(filename).getTypes();
+ IMethod method = types[0].getMethods()[1];
+ search(method, DECLARATIONS | IJavaSearchConstants.IGNORE_DECLARING_TYPE | IJavaSearchConstants.IGNORE_RETURN_TYPE, ERASURE_RULE);
+ assertSearchResults("src/testBug431357_016/X.java void testBug431357_016.I.query(Key) [query] EXACT_MATCH");
+ }
+ finally {
+ // delete files
+ deleteFolder(folder);
+ }
+}
+
}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
index b41b949..2b4f750 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
@@ -1794,7 +1794,7 @@
);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=424198, [1.8][hover] IAE in Signature.createCharArrayTypeSignature when hovering on variable of wildcard type, plus compile errors
-public void _test424198a() throws JavaModelException {
+public void test424198a() throws JavaModelException {
this.wc = getWorkingCopy(
"/Resolve/src/X.java",
"import java.io.IOException;\n" +
@@ -1853,13 +1853,13 @@
IJavaElement[] elements = this.wc.codeSelect(start, length);
assertElementsEqual(
"Unexpected elements",
- "v2 [in apply(? extends java.lang.String) [in <lambda #1> [in processJar(Path) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
+ "v2 [in apply(capture-of ? extends java.lang.String) [in <lambda #1> [in processJar(Path) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
elements,
true
);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=424198, [1.8][hover] IAE in Signature.createCharArrayTypeSignature when hovering on variable of wildcard type, plus compile errors
-public void _test424198b() throws JavaModelException {
+public void test424198b() throws JavaModelException {
this.wc = getWorkingCopy(
"/Resolve/src/X.java",
"import java.io.IOException;\n" +
@@ -1918,7 +1918,7 @@
IJavaElement[] elements = this.wc.codeSelect(start, length);
assertElementsEqual(
"Unexpected elements",
- "s1 [in accept(? extends java.lang.String) [in <lambda #1> [in withWildcard(Stream<? extends String>) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
+ "s1 [in accept(capture-of ? extends java.lang.String) [in <lambda #1> [in withWildcard(Stream<? extends String>) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
elements,
true
);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
index d0f8ad9..e1fb0ac 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
@@ -285,7 +285,7 @@
local.declarationSourceEnd,
local.sourceStart,
local.sourceEnd,
- local.type == null ? Signature.createTypeSignature(binding.type.readableName(), true) : Util.typeSignature(local.type),
+ local.type == null ? Signature.createTypeSignature(binding.type.signableName(), true) : Util.typeSignature(local.type),
binding.declaration.annotations,
local.modifiers,
local.getKind() == AbstractVariableDeclaration.PARAMETER);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
index b754261..2df2cb4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
@@ -708,6 +708,8 @@
/**
* After method lookup has produced 'methodBinding' but when poly expressions have been seen as arguments,
* inspect the arguments to trigger another round of resolving with improved target types from the methods parameters.
+ * If this resolving produces better types for any arguments, update the 'argumentTypes' array in-place as an
+ * intended side effect that will feed better type information in checkInvocationArguments() and others.
* @param invocation the outer invocation which is being resolved
* @param method the method produced by lookup (possibly involving type inference).
* @param argumentTypes the argument types as collected from first resolving the invocation arguments and as used for the method lookup.
@@ -730,7 +732,7 @@
TypeBinding parameterType = InferenceContext18.getParameter(parameters, i, variableArity);
if (parameterType == null)
continue; // not much we can do without a target type, assume it only happens after some resolve error
- if (argumentTypes[i].isPolyType()) {
+ if (argumentTypes[i] != null && argumentTypes[i].isPolyType()) {
argument.setExpectedType(parameterType);
TypeBinding updatedArgumentType = argument.resolveType(scope);
if (argument instanceof LambdaExpression) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
index 6b89407..621fc3d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -710,8 +710,18 @@
// Given the allocation type and the arguments to the constructor, see if we can infer the constructor of the elided parameterized type.
MethodBinding factory = scope.getStaticFactory(allocationType, enclosingType, argumentTyps, this);
if (factory instanceof ParameterizedGenericMethodBinding && factory.isValidBinding()) {
- SyntheticFactoryMethodBinding original = (SyntheticFactoryMethodBinding) factory.original();
- return original.applyTypeArgumentsOnConstructor(((ParameterizedTypeBinding)factory.returnType).arguments);
+ SyntheticFactoryMethodBinding sfmb = (SyntheticFactoryMethodBinding) factory.original();
+ TypeVariableBinding[] constructorTypeVariables = sfmb.getConstructor().typeVariables();
+ TypeBinding [] constructorTypeArguments = constructorTypeVariables != null ? new TypeBinding[constructorTypeVariables.length] : Binding.NO_TYPES;
+ if (constructorTypeArguments.length > 0)
+ System.arraycopy(((ParameterizedGenericMethodBinding)factory).typeArguments, sfmb.typeVariables().length - constructorTypeArguments.length ,
+ constructorTypeArguments, 0, constructorTypeArguments.length);
+ MethodBinding constructor = sfmb.applyTypeArgumentsOnConstructor(((ParameterizedTypeBinding)factory.returnType).arguments, constructorTypeArguments);
+ if (constructor instanceof ParameterizedGenericMethodBinding && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) {
+ // force an inference context to be established, but avoid tunneling through overload resolution. We know this is the MSMB.
+ return ParameterizedGenericMethodBinding.computeCompatibleMethod18(constructor.shallowOriginal(), argumentTyps, scope, this);
+ }
+ return constructor;
}
return null;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
index c5f85a8..07f61e3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
@@ -558,9 +558,8 @@
}
if (valueRequired) {
codeStream.generateImplicitConversion(this.implicitConversion);
- } else if (needRuntimeCheckcast) {
- boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0;
- switch (isUnboxing ? postConversionType(currentScope).id : this.resolvedType.id) {
+ } else if (annotatedCast || needRuntimeCheckcast) {
+ switch (this.resolvedType.id) {
case T_long :
case T_double :
codeStream.pop2();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
index 7f0ccbf..7caa2ff 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -719,7 +719,7 @@
public boolean isPertinentToApplicability(TypeVariableBinding typeVariable, MethodBinding method) {
return this.valueIfTrue.isPertinentToApplicability(typeVariable, method)
- && this.valueIfFalse.isPertinentToApplicability(typeVariable, method); // not perfect.
+ && this.valueIfFalse.isPertinentToApplicability(typeVariable, method);
}
public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) {
@@ -729,7 +729,7 @@
@Override
public boolean isFunctionalType() {
- return this.valueIfTrue.isFunctionalType() || this.valueIfFalse.isFunctionalType();
+ return this.valueIfTrue.isFunctionalType() || this.valueIfFalse.isFunctionalType(); // Even if only one arm is functional type, this will require a functional interface target
}
public boolean isPolyExpression() throws UnsupportedOperationException {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index 1db2668..60a8cda 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -694,6 +694,14 @@
/** During inference: Try to find an applicable method binding without causing undesired side-effects. */
public MethodBinding findCompileTimeMethodTargeting(TypeBinding targetType, Scope scope) {
+ if (this.exactMethodBinding != null) {
+ MethodBinding functionType = targetType.getSingleAbstractMethod(scope, true);
+ if (functionType == null)
+ return null;
+ int n = functionType.parameters.length;
+ int k = this.exactMethodBinding.parameters.length;
+ return (n == k || n == k + 1) ? this.exactMethodBinding : null;
+ }
MethodBinding targetMethod = internalResolveTentatively(targetType, scope);
if (targetMethod == null || !targetMethod.isValidBinding())
return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
index 2110b8b..9860d08 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
@@ -422,7 +422,13 @@
}
return hasProperBound;
}
-
+
+ public void addBounds(BoundSet that, LookupEnvironment environment) {
+ if (that == null || environment == null)
+ return;
+ addBounds(that.flatten(), environment);
+ }
+
public boolean isInstantiated(InferenceVariable inferenceVariable) {
ThreeSets three = this.boundsPerVariable.get(inferenceVariable.prototype());
if (three != null)
@@ -594,9 +600,7 @@
while (captIter.hasNext()) {
Entry<ParameterizedTypeBinding, ParameterizedTypeBinding> capt = captIter.next();
ParameterizedTypeBinding gAlpha = capt.getKey();
- // We come in with capture(gA), we need to work with gA below. It was necessary to establish capture at the call site.
- ParameterizedTypeBinding cgA = capt.getValue();
- ParameterizedTypeBinding gA = (ParameterizedTypeBinding) cgA.uncapture(context.scope);
+ ParameterizedTypeBinding gA = capt.getValue();
ReferenceBinding g = (ReferenceBinding) gA.original();
final TypeVariableBinding[] parameters = g.typeVariables();
// construct theta = [P1:=alpha1,...]
@@ -615,7 +619,6 @@
addBounds(pi.getTypeBounds(alpha, theta), context.environment);
TypeBinding ai = gA.arguments[i];
- TypeBinding cai = cgA.arguments[i];
if (ai instanceof WildcardBinding) {
WildcardBinding wildcardBinding = (WildcardBinding)ai;
TypeBinding t = wildcardBinding.bound;
@@ -627,14 +630,11 @@
it = three.sameBounds.iterator();
while (it.hasNext()) {
TypeBound bound = it.next();
- /* With the expected type's declared type being Collector<? super T, A, R> and gAlpha being Collector<T#0,?#1,List<T#0>#2> and cgA being
- Collector<T#0,capture#1-of ?,List<T#0>>, without the constraint reduction below - we will never discover A to be capture#1-of ? and
- claim A is jlO. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=437444#c24 - #27
- */
- if (!reduceOneConstraint(context, ConstraintTypeFormula.create(bound.right, cai, ReductionResult.SAME)))
- return false;
- // Our = reduction transitively adds a new bound that necessitates the check below for capture.
- if (!(bound.right instanceof InferenceVariable) && !bound.right.isCapture())
+ if (InferenceContext18.SHOULD_WORKAROUND_BUG_JDK_8054721) {
+ if (bound.right instanceof CaptureBinding && bound.right.isProperType(true))
+ continue;
+ }
+ if (!(bound.right instanceof InferenceVariable))
return false;
}
}
@@ -656,7 +656,7 @@
ReferenceBinding[] allBounds = new ReferenceBinding[n];
allBounds[0] = (ReferenceBinding) bi1; // TODO is this safe?
System.arraycopy(otherBounds, 0, allBounds, 1, n-1);
- bi = new IntersectionCastTypeBinding(allBounds, context.environment);
+ bi = context.environment.createIntersectionCastType(allBounds);
}
addTypeBoundsFromWildcardBound(context, theta, wildcardBinding.boundKind, t, r, bi);
// if (otherBounds != null) {
@@ -978,21 +978,6 @@
if (three == null) return null;
return three.findSingleWrapperType();
}
-
- private TypeBinding applyInstantiations(TypeBinding type) {
- if (type.isProperType(true))
- return type;
-
- Iterator<InferenceVariable> variableIt = this.boundsPerVariable.keySet().iterator();
- while (variableIt.hasNext()) {
- InferenceVariable inferenceVariable = variableIt.next();
- TypeBinding instantiation = getInstantiation(inferenceVariable, null);
- if (instantiation != null)
- type = type.substituteInferenceVariable(inferenceVariable, instantiation);
- }
- return type;
- }
-
// this condition is just way too complex to check it in-line:
public boolean condition18_5_2_bullet_3_3_1(InferenceVariable alpha, TypeBinding targetType) {
// T is a reference type, but is not a wildcard-parameterized type, and either
@@ -1032,10 +1017,9 @@
/* HashMap<K#8,V#9> and HashMap<K#8,ArrayList<T>> with an instantiation for V9 = ArrayList<T> already in the
bound set should not be seen as two different parameterizations of the same generic class or interface.
See https://bugs.eclipse.org/bugs/show_bug.cgi?id=432626 for a test that triggers this condition.
+ See https://bugs.openjdk.java.net/browse/JDK-8056092: recommendation is to check for proper types.
*/
- supers[0] = applyInstantiations(supers[0]);
- supers[1] = applyInstantiations(supers[1]);
- if (!TypeBinding.equalsEquals(supers[0], supers[1]))
+ if (supers[0].isProperType(true) && supers[1].isProperType(true) && !TypeBinding.equalsEquals(supers[0], supers[1]))
return true;
}
}
@@ -1075,7 +1059,8 @@
private boolean superOnlyRaw(TypeBinding g, TypeBinding s, LookupEnvironment env) {
if (s instanceof InferenceVariable)
return false; // inference has no super types
- if (s.findSuperTypeOriginatingFrom(g) == null)
+ final TypeBinding superType = s.findSuperTypeOriginatingFrom(g);
+ if (superType != null && !superType.isParameterizedType())
return s.isCompatibleWith(env.convertToRawType(g, false));
return false;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
index f35a24c..0cc500d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
@@ -291,6 +291,20 @@
}
return super.readableName();
}
+
+ public char[] signableName() {
+ if (this.wildcard != null) {
+ StringBuffer buffer = new StringBuffer(10);
+ buffer
+ .append(TypeConstants.WILDCARD_CAPTURE_SIGNABLE_NAME_SUFFIX)
+ .append(this.wildcard.readableName());
+ int length = buffer.length();
+ char[] name = new char[length];
+ buffer.getChars(0, length, name, 0);
+ return name;
+ }
+ return super.readableName();
+ }
public char[] shortReadableName() {
if (this.wildcard != null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
index 9fe42d1..3eaf2db 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
@@ -93,7 +93,7 @@
}
if (!multipleErasures)
return erasures[0];
- return new IntersectionCastTypeBinding(erasures, this.environment);
+ return this.environment.createIntersectionCastType(erasures);
}
return super.erasure();
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
index 2820638..783210e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
@@ -83,20 +83,32 @@
if (previousMethod instanceof ParameterizedGenericMethodBinding) {
// find the previous inner inference context to see what inference kind this invocation needs:
InferenceContext18 innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) previousMethod);
- if (innerCtx == null) { // no inference -> assume it wasn't really poly after all
+ if (innerCtx == null || innerCtx.stepCompleted >= InferenceContext18.TYPE_INFERRED) {
+ /* No inference context -> the method was likely manufactured by Scope.findExactMethod -> assume it wasn't really poly after all.
+ Otherwise, either the constraints and initial bounds that would effectively reduce to b3 are already transferred to current context
+ during C Set construction. Otherwise all that is relevant is to relate the return type with expected type.
+ */
TypeBinding exprType = this.left.resolvedType;
if (exprType == null || !exprType.isValidBinding())
return FALSE;
return ConstraintTypeFormula.create(exprType, this.right, COMPATIBLE, this.isSoft);
}
- if (innerCtx.stepCompleted >= InferenceContext18.TYPE_INFERRED) {
- // The constraints and initial bounds that would effectively reduce to b3 are already transferred to current context during C Set construction.
- return TRUE;
+ if (innerCtx.stepCompleted >= InferenceContext18.APPLICABILITY_INFERRED) {
+ inferenceContext.currentBounds.addBounds(innerCtx.b2, inferenceContext.environment);
+ inferenceContext.inferenceVariables = innerCtx.inferenceVariables;
+ inferenceContext.inferenceKind = innerCtx.inferenceKind;
+ innerCtx.outerContext = inferenceContext;
+ inferenceContext.usesUncheckedConversion = innerCtx.usesUncheckedConversion;
+ } else {
+ return FALSE; // should not reach here.
}
- inferenceContext.inferenceKind = innerCtx.inferenceKind;
+ // b2 has been lifted, inferring poly invocation type amounts to lifting b3.
+ } else {
+ inferenceContext.inferenceKind = inferenceContext.getInferenceKind(previousMethod, argumentTypes);
+ boolean isDiamond = method.isConstructor() && this.left.isPolyExpression(method);
+ inferInvocationApplicability(inferenceContext, method, argumentTypes, isDiamond, inferenceContext.inferenceKind);
+ // b2 has been lifted, inferring poly invocation type amounts to lifting b3.
}
- boolean isDiamond = method.isConstructor() && this.left.isPolyExpression(method);
- inferInvocationApplicability(inferenceContext, method, argumentTypes, isDiamond, inferenceContext.inferenceKind);
if (!inferPolyInvocationType(inferenceContext, invocation, this.right, method))
return FALSE;
return null; // already incorporated
@@ -214,9 +226,11 @@
MethodBinding functionType = t.getSingleAbstractMethod(inferenceContext.scope, true);
if (functionType == null)
return FALSE;
-
+ // potentially-applicable method for the method reference when targeting T (15.13.1),
+ MethodBinding potentiallyApplicable = reference.findCompileTimeMethodTargeting(t, inferenceContext.scope);
+ if (potentiallyApplicable == null)
+ return FALSE;
if (reference.isExactMethodReference()) {
- MethodBinding potentiallyApplicable = reference.getExactMethod();
List<ConstraintFormula> newConstraints = new ArrayList<ConstraintFormula>();
TypeBinding[] p = functionType.parameters;
int n = p.length;
@@ -226,8 +240,6 @@
if (n == k+1) {
newConstraints.add(ConstraintTypeFormula.create(p[0], reference.lhs.resolvedType, COMPATIBLE));
offset = 1;
- } else if (n != k) {
- return FALSE;
}
for (int i = offset; i < n; i++)
newConstraints.add(ConstraintTypeFormula.create(p[i], pPrime[i-offset], COMPATIBLE));
@@ -241,10 +253,6 @@
}
return newConstraints.toArray(new ConstraintFormula[newConstraints.size()]);
} else { // inexact
- MethodBinding potentiallyApplicable = reference.findCompileTimeMethodTargeting(t, inferenceContext.scope); // // potentially-applicable method for the method reference when targeting T (15.13.1),
- if (potentiallyApplicable == null)
- return FALSE;
-
int n = functionType.parameters.length;
for (int i = 0; i < n; i++)
if (!functionType.parameters[i].isProperType(true))
@@ -331,7 +339,7 @@
if (returnType == TypeBinding.VOID)
throw new InferenceFailureException("expression has no value"); //$NON-NLS-1$
- if (inferenceContext.usesUncheckedConversion()) {
+ if (inferenceContext.usesUncheckedConversion) {
// spec says erasure, but we don't really have compatibility rules for erasure, use raw type instead:
TypeBinding erasure = inferenceContext.environment.convertToRawType(returnType, false);
ConstraintTypeFormula newConstraint = ConstraintTypeFormula.create(erasure, targetType, COMPATIBLE);
@@ -348,18 +356,29 @@
InferenceVariable[] betas = inferenceContext.addTypeVariableSubstitutions(arguments);
ParameterizedTypeBinding gbeta = inferenceContext.environment.createParameterizedType(
parameterizedType.genericType(), betas, parameterizedType.enclosingType(), parameterizedType.getTypeAnnotations());
- inferenceContext.currentBounds.captures.put(gbeta, parameterizedType.capture(inferenceContext.scope, invocationSite.sourceEnd())); // established: both types have nonnull arguments
+ inferenceContext.currentBounds.captures.put(gbeta, parameterizedType); // established: both types have nonnull arguments
+ if (InferenceContext18.SHOULD_WORKAROUND_BUG_JDK_8054721) {
+ parameterizedType = parameterizedType.capture(inferenceContext.scope, invocationSite.sourceEnd());
+ arguments = parameterizedType.arguments;
+ for (int i = 0, length = arguments.length; i < length; i++) {
+ if (arguments[i].isCapture() && arguments[i].isProperType(true)) {
+ CaptureBinding capture = (CaptureBinding) arguments[i];
+ inferenceContext.currentBounds.addBound(new TypeBound(betas[i], capture, SAME), inferenceContext.environment);
+ }
+ }
+ }
ConstraintTypeFormula newConstraint = ConstraintTypeFormula.create(gbeta, targetType, COMPATIBLE);
return inferenceContext.reduceAndIncorporate(newConstraint);
}
- if (rTheta instanceof InferenceVariable) {
- InferenceVariable alpha = (InferenceVariable) rTheta;
+ if (rTheta.leafComponentType() instanceof InferenceVariable) { // https://bugs.openjdk.java.net/browse/JDK-8062082
+ InferenceVariable alpha = (InferenceVariable) rTheta.leafComponentType();
+ TypeBinding targetLeafType = targetType.leafComponentType();
boolean toResolve = false;
- if (inferenceContext.currentBounds.condition18_5_2_bullet_3_3_1(alpha, targetType)) {
+ if (inferenceContext.currentBounds.condition18_5_2_bullet_3_3_1(alpha, targetLeafType)) {
toResolve = true;
- } else if (inferenceContext.currentBounds.condition18_5_2_bullet_3_3_2(alpha, targetType, inferenceContext)) {
+ } else if (inferenceContext.currentBounds.condition18_5_2_bullet_3_3_2(alpha, targetLeafType, inferenceContext)) {
toResolve = true;
- } else if (targetType.isPrimitiveType()) {
+ } else if (targetLeafType.isPrimitiveType()) {
TypeBinding wrapper = inferenceContext.currentBounds.findWrapperTypeBound(alpha);
if (wrapper != null)
toResolve = true;
@@ -369,6 +388,9 @@
if (solution == null)
return false;
TypeBinding u = solution.getInstantiation(alpha, null).capture(inferenceContext.scope, invocationSite.sourceEnd());
+ if (rTheta.dimensions() != 0) {
+ u = inferenceContext.environment.createArrayType(u, rTheta.dimensions());
+ }
ConstraintTypeFormula newConstraint = ConstraintTypeFormula.create(u, targetType, COMPATIBLE);
return inferenceContext.reduceAndIncorporate(newConstraint);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
index acd0260..1b5eba7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
@@ -30,26 +30,6 @@
public abstract Object reduce(InferenceContext18 inferenceContext) throws InferenceFailureException;
- /** 5.3: compatibility check which includes the option of boxing/unboxing. */
- protected boolean isCompatibleWithInLooseInvocationContext(TypeBinding one, TypeBinding two, InferenceContext18 context) {
- if (one.isCompatibleWith(two, context.scope))
- return true;
- if (one.isBaseType() == two.isBaseType()) // this also protects against comparing null & primitive
- return false;
- if (one.isPrimitiveType()) {
- if (!two.isBaseType()) {
- TypeBinding boxingType = context.environment.computeBoxingType(one);
- if (boxingType != one) //$IDENTITY-COMPARISON$ just checking if boxing could help
- return boxingType.isCompatibleWith(two, context.scope);
- }
- } else if (two.isPrimitiveType()) {
- TypeBinding boxingType = context.environment.computeBoxingType(two);
- if (boxingType != two) //$IDENTITY-COMPARISON$ just checking if boxing could help
- return one.isCompatibleWith(boxingType, context.scope);
- }
- return false;
- }
-
Collection<InferenceVariable> inputVariables(InferenceContext18 context) {
return EMPTY_VARIABLE_LIST;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
index 20ba95e..4e7994a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
@@ -61,15 +61,17 @@
case COMPATIBLE:
// 18.2.2:
if (this.left.isProperType(true) && this.right.isProperType(true)) {
- if (isCompatibleWithInLooseInvocationContext(this.left, this.right, inferenceContext))
- return TRUE;
- return FALSE;
+ return this.left.isCompatibleWith(this.right, inferenceContext.scope) || this.left.isBoxingCompatibleWith(this.right, inferenceContext.scope) ? TRUE : FALSE;
}
if (this.left.isPrimitiveType()) {
+ if (inferenceContext.inferenceKind == InferenceContext18.CHECK_STRICT)
+ inferenceContext.inferenceKind = InferenceContext18.CHECK_LOOSE;
TypeBinding sPrime = inferenceContext.environment.computeBoxingType(this.left);
return ConstraintTypeFormula.create(sPrime, this.right, COMPATIBLE, this.isSoft);
}
if (this.right.isPrimitiveType()) {
+ if (inferenceContext.inferenceKind == InferenceContext18.CHECK_STRICT)
+ inferenceContext.inferenceKind = InferenceContext18.CHECK_LOOSE;
TypeBinding tPrime = inferenceContext.environment.computeBoxingType(this.right);
return ConstraintTypeFormula.create(this.left, tPrime, SAME, this.isSoft);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
index 32bf11d..8f2268a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
@@ -79,11 +79,11 @@
* <dt>18.5.1 Invocation Applicability Inference</dt>
* <dd>{@link #inferInvocationApplicability(MethodBinding, TypeBinding[], boolean)}. Prepare the initial state for
* inference of a generic invocation - no target type used at this point.
- * Need to call {@link #solve()} afterwards to produce the intermediate result.<br/>
+ * Need to call {@link #solve(boolean)} with true afterwards to produce the intermediate result.<br/>
* Called indirectly from {@link Scope#findMethod(ReferenceBinding, char[], TypeBinding[], InvocationSite, boolean)} et al
* to select applicable methods into overload resolution.</dd>
* <dt>18.5.2 Invocation Type Inference</dt>
- * <dd>{@link InferenceContext18#inferInvocationType(BoundSet, TypeBinding, InvocationSite, MethodBinding)}. After a
+ * <dd>{@link InferenceContext18#inferInvocationType(TypeBinding, InvocationSite, MethodBinding)}. After a
* most specific method has been picked, and given a target type determine the final generic instantiation.
* As long as a target type is still unavailable this phase keeps getting deferred.</br>
* Different wrappers exist for the convenience of different callers.</dd>
@@ -106,6 +106,12 @@
/** to conform with javac regarding https://bugs.openjdk.java.net/browse/JDK-8026527 */
static final boolean SIMULATE_BUG_JDK_8026527 = true;
+
+ /** Temporary workaround until we know fully what to do with https://bugs.openjdk.java.net/browse/JDK-8054721
+ * It looks likely that we have a bug independent of this JLS bug in that we clear the capture bounds eagerly.
+ */
+ static final boolean SHOULD_WORKAROUND_BUG_JDK_8054721 = true; // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=437444#c24 onwards
+
/**
* Detail flag to control the extent of {@link #SIMULATE_BUG_JDK_8026527}.
* A setting of 'false' implements the advice from http://mail.openjdk.java.net/pipermail/lambda-spec-experts/2013-December/000447.html
@@ -148,11 +154,14 @@
/** Signals whether any type compatibility makes use of unchecked conversion. */
public List<ConstraintFormula> constraintsWithUncheckedConversion;
-
+ public boolean usesUncheckedConversion;
+ public InferenceContext18 outerContext;
Scope scope;
LookupEnvironment environment;
ReferenceBinding object; // java.lang.Object
+ public BoundSet b2;
+ public static final int CHECK_UNKNOWN = 0;
public static final int CHECK_STRICT = 1;
public static final int CHECK_LOOSE = 2;
public static final int CHECK_VARARG = 3;
@@ -162,11 +171,13 @@
Expression[] invocationArguments;
InferenceVariable[] inferenceVariables;
int inferenceKind;
- SuspendedInferenceRecord(InvocationSite site, Expression[] invocationArguments, InferenceVariable[] inferenceVariables, int inferenceKind) {
+ boolean usesUncheckedConversion;
+ SuspendedInferenceRecord(InvocationSite site, Expression[] invocationArguments, InferenceVariable[] inferenceVariables, int inferenceKind, boolean usesUncheckedConversion) {
this.site = site;
this.invocationArguments = invocationArguments;
this.inferenceVariables = inferenceVariables;
this.inferenceKind = inferenceKind;
+ this.usesUncheckedConversion = usesUncheckedConversion;
}
}
@@ -224,7 +235,6 @@
/** JLS 18.5.1: compute bounds from formal and actual parameters. */
public void createInitialConstraintsForParameters(TypeBinding[] parameters, boolean checkVararg, TypeBinding varArgsType, MethodBinding method) {
- // TODO discriminate strict vs. loose invocations
if (this.invocationArguments == null)
return;
int len = checkVararg ? parameters.length - 1 : Math.min(parameters.length, this.invocationArguments.length);
@@ -326,17 +336,14 @@
}
/** JLS 18.5.2 Invocation Type Inference
- * @param b1 "the bound set produced by reduction in order to demonstrate that m is applicable in 18.5.1"
*/
- public BoundSet inferInvocationType(BoundSet b1, TypeBinding expectedType, InvocationSite invocationSite, MethodBinding method)
- throws InferenceFailureException
+ public BoundSet inferInvocationType(TypeBinding expectedType, InvocationSite invocationSite, MethodBinding method) throws InferenceFailureException
{
// not JLS: simply ensure that null hints from the return type have been seen even in standalone contexts:
if (expectedType == null && method.returnType != null)
substitute(method.returnType); // result is ignore, the only effect is on InferenceVariable.nullHints
- //
- BoundSet previous = this.currentBounds.copy();
- this.currentBounds = b1;
+
+ this.currentBounds = this.b2.copy();
try {
// bullets 1&2: definitions only.
if (expectedType != null
@@ -392,7 +399,7 @@
// 6. bullet: solve
BoundSet solution = solve();
if (solution == null || !isResolved(solution)) {
- this.currentBounds = previous; // don't let bounds from unsuccessful attempt leak into subsequent attempts
+ this.currentBounds = this.b2; // don't let bounds from unsuccessful attempt leak into subsequent attempts
return null;
}
// we're done, start reporting:
@@ -433,11 +440,6 @@
private boolean addConstraintsToC_OneExpr(Expression expri, Set<ConstraintFormula> c, TypeBinding fsi, TypeBinding substF, MethodBinding method, boolean interleaved) throws InferenceFailureException {
- // See https://bugs.openjdk.java.net/browse/JDK-8052325 for exclusion of poly expressions targeting proper types. CEF.reduce validates
- // that they are compatible in a loose invocation context against the target type. They contribute nothing further to solving the formulas.
- if (substF.isProperType(true))
- return true;
-
// For all i (1 ≤ i ≤ k), if ei is not pertinent to applicability, the set contains ⟨ei → θ Fi⟩.
if (!expri.isPertinentToApplicability(fsi, method)) {
c.add(new ConstraintExpressionFormula(expri, substF, ReductionResult.COMPATIBLE, ARGUMENT_CONSTRAINTS_ARE_SOFT));
@@ -466,23 +468,32 @@
}
}
} else if (expri instanceof Invocation && expri.isPolyExpression()) {
+
+ if (substF.isProperType(true)) // https://bugs.openjdk.java.net/browse/JDK-8052325
+ return true;
+
Invocation invocation = (Invocation) expri;
MethodBinding innerMethod = invocation.binding(substF, this.scope);
if (innerMethod == null)
return true; // -> proceed with no new C set elements.
+ Expression[] arguments = invocation.arguments();
+ TypeBinding[] argumentTypes = arguments == null ? Binding.NO_PARAMETERS : new TypeBinding[arguments.length];
+ for (int i = 0; i < argumentTypes.length; i++)
+ argumentTypes[i] = arguments[i].resolvedType;
+ int applicabilityKind;
+ InferenceContext18 innerContext = null;
+ if (innerMethod instanceof ParameterizedGenericMethodBinding)
+ innerContext = invocation.getInferenceContext((ParameterizedGenericMethodBinding) innerMethod);
+ applicabilityKind = innerContext != null ? innerContext.inferenceKind : getInferenceKind(innerMethod, argumentTypes);
+
if (interleaved) {
MethodBinding shallowMethod = innerMethod.shallowOriginal();
SuspendedInferenceRecord prevInvocation = enterPolyInvocation(invocation, invocation.arguments());
try {
- Expression[] arguments = invocation.arguments();
- TypeBinding[] argumentTypes = arguments == null ? Binding.NO_PARAMETERS : new TypeBinding[arguments.length];
- for (int i = 0; i < argumentTypes.length; i++)
- argumentTypes[i] = arguments[i].resolvedType;
- if (innerMethod instanceof ParameterizedGenericMethodBinding) {
- InferenceContext18 innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) innerMethod);
- this.inferenceKind = innerCtx.inferenceKind;
- }
+ this.inferenceKind = applicabilityKind;
+ if (innerContext != null)
+ innerContext.outerContext = this;
inferInvocationApplicability(shallowMethod, argumentTypes, shallowMethod.isConstructor());
if (!ConstraintExpressionFormula.inferPolyInvocationType(this, invocation, substF, shallowMethod))
return false;
@@ -490,13 +501,6 @@
resumeSuspendedInference(prevInvocation);
}
}
- int applicabilityKind = CHECK_LOOSE; // FIXME, for <> resolving to a non-generic method, this need to be computed.
- if (innerMethod instanceof ParameterizedGenericMethodBinding) {
- InferenceContext18 innerCtx = invocation.getInferenceContext((ParameterizedMethodBinding) innerMethod);
- if (innerCtx != null) {
- applicabilityKind = innerCtx.inferenceKind;
- }
- }
return addConstraintsToC(invocation.arguments(), c, innerMethod.genericMethod(), applicabilityKind, interleaved);
} else if (expri instanceof ConditionalExpression) {
ConditionalExpression ce = (ConditionalExpression) expri;
@@ -506,6 +510,18 @@
return true;
}
+
+ protected int getInferenceKind(MethodBinding nonGenericMethod, TypeBinding[] argumentTypes) {
+ switch (this.scope.parameterCompatibilityLevel(nonGenericMethod, argumentTypes)) {
+ case Scope.AUTOBOX_COMPATIBLE:
+ return CHECK_LOOSE;
+ case Scope.VARARGS_COMPATIBLE:
+ return CHECK_VARARG;
+ default:
+ return CHECK_STRICT;
+ }
+ }
+
public boolean hasResultFor(TypeBinding targetType) {
if (targetType == null)
return this.stepCompleted >= TYPE_INFERRED;
@@ -769,15 +785,21 @@
* @return a bound set representing the solution, or null if inference failed
* @throws InferenceFailureException a compile error has been detected during inference
*/
- public /*@Nullable*/ BoundSet solve() throws InferenceFailureException {
+ public /*@Nullable*/ BoundSet solve(boolean inferringApplicability) throws InferenceFailureException {
if (!reduce())
return null;
if (!this.currentBounds.incorporate(this))
return null;
+ if (inferringApplicability)
+ this.b2 = this.currentBounds.copy(); // Preserve the result after reduction, without effects of resolve() for later use in invocation type inference.
return resolve(this.inferenceVariables);
}
+ public /*@Nullable*/ BoundSet solve() throws InferenceFailureException {
+ return solve(false);
+ }
+
public /*@Nullable*/ BoundSet solve(InferenceVariable[] toResolve) throws InferenceFailureException {
if (!reduce())
return null;
@@ -792,11 +814,14 @@
* @throws InferenceFailureException
*/
private boolean reduce() throws InferenceFailureException {
- if (this.initialConstraints != null) {
- for (int i = 0; i < this.initialConstraints.length; i++) {
- if (!this.currentBounds.reduceOneConstraint(this, this.initialConstraints[i]))
- return false;
- }
+ // Caution: This can be reentered recursively even as an earlier call is munching through the constraints !
+ for (int i = 0; this.initialConstraints != null && i < this.initialConstraints.length; i++) {
+ final ConstraintFormula currentConstraint = this.initialConstraints[i];
+ if (currentConstraint == null)
+ continue;
+ this.initialConstraints[i] = null;
+ if (!this.currentBounds.reduceOneConstraint(this, currentConstraint))
+ return false;
}
this.initialConstraints = null;
return true;
@@ -895,7 +920,7 @@
} else if (glbs.length == 1) {
glb = glbs[0];
} else {
- IntersectionCastTypeBinding intersection = new IntersectionCastTypeBinding(glbs, this.environment);
+ IntersectionCastTypeBinding intersection = (IntersectionCastTypeBinding) this.environment.createIntersectionCastType(glbs);
if (!ReferenceBinding.isConsistentIntersection(intersection.intersectingTypes)) {
tmpBoundSet = prevBoundSet; // clean up
break variables; // and start over
@@ -917,6 +942,7 @@
final CaptureBinding18[] zs = new CaptureBinding18[numVars];
for (int j = 0; j < numVars; j++)
zs[j] = freshCapture(variables[j]);
+ final BoundSet kurrentBoundSet = tmpBoundSet;
Substitution theta = new Substitution() {
public LookupEnvironment environment() {
return InferenceContext18.this.environment;
@@ -928,6 +954,16 @@
for (int j = 0; j < numVars; j++)
if (TypeBinding.equalsEquals(variables[j], typeVariable))
return zs[j];
+ /* If we have an instantiation, lower it to the instantiation. We don't want downstream abstractions to be confused about multiple versions of bounds without
+ and with instantiations propagated by incorporation. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=430686. There is no value whatsoever in continuing
+ to speak in two tongues. Also fixes https://bugs.eclipse.org/bugs/show_bug.cgi?id=425031.
+ */
+ if (typeVariable instanceof InferenceVariable) {
+ InferenceVariable inferenceVariable = (InferenceVariable) typeVariable;
+ TypeBinding instantiation = kurrentBoundSet.getInstantiation(inferenceVariable, null);
+ if (instantiation != null)
+ return instantiation;
+ }
return typeVariable;
}
//{ObjectTeams:
@@ -942,7 +978,6 @@
// add lower bounds:
TypeBinding[] lowerBounds = tmpBoundSet.lowerBounds(variable, true/*onlyProper*/);
if (lowerBounds != Binding.NO_TYPES) {
- lowerBounds = Scope.substitute(theta, lowerBounds);
TypeBinding lub = this.scope.lowerUpperBound(lowerBounds);
if (lub != TypeBinding.VOID && lub != null)
zsj.lowerBound = lub;
@@ -1290,19 +1325,20 @@
}
public SuspendedInferenceRecord enterPolyInvocation(InvocationSite invocation, Expression[] innerArguments) {
- SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind);
+ SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind, this.usesUncheckedConversion);
this.inferenceVariables = null;
this.invocationArguments = innerArguments;
this.currentInvocation = invocation;
-
+ this.usesUncheckedConversion = false;
return record;
}
public SuspendedInferenceRecord enterLambda(LambdaExpression lambda) {
- SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind);
+ SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind, this.usesUncheckedConversion);
this.inferenceVariables = null;
this.invocationArguments = null;
this.currentInvocation = null;
+ this.usesUncheckedConversion = false;
return record;
}
@@ -1322,6 +1358,7 @@
this.currentInvocation = record.site;
this.invocationArguments = record.invocationArguments;
this.inferenceKind = record.inferenceKind;
+ this.usesUncheckedConversion = record.usesUncheckedConversion;
}
private Substitution getResultSubstitution(final BoundSet result) {
@@ -1459,6 +1496,7 @@
if (this.constraintsWithUncheckedConversion == null)
this.constraintsWithUncheckedConversion = new ArrayList<ConstraintFormula>();
this.constraintsWithUncheckedConversion.add(constraint);
+ this.usesUncheckedConversion = true;
}
void reportUncheckedConversions(BoundSet solution) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
index 57dc128..d8ad779 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
@@ -190,11 +190,25 @@
ParameterizedGenericMethodBinding methodSubstitute = null;
TypeVariableBinding[] typeVariables = originalMethod.typeVariables;
- InferenceContext18 infCtx18 = null;
+ InferenceContext18 infCtx18 = invocationSite.freshInferenceContext(scope);
TypeBinding[] parameters = originalMethod.parameters;
- infCtx18 = invocationSite.freshInferenceContext(scope);
CompilerOptions compilerOptions = scope.compilerOptions();
boolean invocationTypeInferred = false;
+ boolean requireBoxing = false;
+
+ // See if we should start in loose inference mode.
+ TypeBinding [] argumentsCopy = new TypeBinding[arguments.length];
+ for (int i = 0, length = arguments.length, parametersLength = parameters.length ; i < length; i++) {
+ TypeBinding parameter = i < parametersLength ? parameters[i] : parameters[parametersLength - 1];
+ final TypeBinding argument = arguments[i];
+ if (argument.isPrimitiveType() != parameter.isPrimitiveType()) { // Scope.cCM incorrectly but harmlessly uses isBaseType which answers true for null.
+ argumentsCopy[i] = scope.environment().computeBoxingType(argument);
+ requireBoxing = true; // can't be strict mode, needs at least loose.
+ } else {
+ argumentsCopy[i] = argument;
+ }
+ }
+ arguments = argumentsCopy; // either way, this allows the engine to update arguments without harming the callers.
try {
BoundSet provisionalResult = null;
@@ -203,23 +217,23 @@
final boolean isPolyExpression = invocationSite instanceof Expression && ((Expression)invocationSite).isPolyExpression(originalMethod);
boolean isDiamond = isPolyExpression && originalMethod.isConstructor();
if (arguments.length == parameters.length) {
- infCtx18.inferenceKind = InferenceContext18.CHECK_LOOSE; // TODO: validate if 2 phase checking (strict/loose + vararg) is sufficient.
+ infCtx18.inferenceKind = requireBoxing ? InferenceContext18.CHECK_LOOSE : InferenceContext18.CHECK_STRICT; // engine may still slip into loose mode and adjust level.
infCtx18.inferInvocationApplicability(originalMethod, arguments, isDiamond);
- result = infCtx18.solve();
+ result = infCtx18.solve(true);
}
if (result == null && originalMethod.isVarargs()) {
// check for variable-arity applicability
infCtx18 = invocationSite.freshInferenceContext(scope); // start over
infCtx18.inferenceKind = InferenceContext18.CHECK_VARARG;
infCtx18.inferInvocationApplicability(originalMethod, arguments, isDiamond);
- result = infCtx18.solve();
+ result = infCtx18.solve(true);
}
if (result == null)
return null;
if (infCtx18.isResolved(result)) {
infCtx18.stepCompleted = InferenceContext18.APPLICABILITY_INFERRED;
if (invocationSite instanceof ReferenceExpression)
- ((ReferenceExpression) invocationSite).inferenceKind = infCtx18.inferenceKind; // CHECK
+ ((ReferenceExpression) invocationSite).inferenceKind = infCtx18.inferenceKind;
} else {
return null;
}
@@ -229,8 +243,7 @@
if (expectedType != null || !invocationSite.getExpressionContext().definesTargetType()) {
// ---- 18.5.2 (Invocation type): ----
provisionalResult = result;
- result = infCtx18.currentBounds.copy(); // the result after reduction, without effects of resolve()
- result = infCtx18.inferInvocationType(result, expectedType, invocationSite, originalMethod);
+ result = infCtx18.inferInvocationType(expectedType, invocationSite, originalMethod);
invocationTypeInferred = true;
hasReturnProblem |= result == null;
if (hasReturnProblem)
@@ -254,7 +267,6 @@
if (hasReturnProblem) { // illegally working from the provisional result?
MethodBinding problemMethod = infCtx18.getReturnProblemMethodIfNeeded(expectedType, methodSubstitute);
if (problemMethod instanceof ProblemMethodBinding) {
- methodSubstitute = null;
return problemMethod;
}
}
@@ -268,7 +280,6 @@
MethodBinding problemMethod = methodSubstitute.boundCheck18(scope, invocationSite, arguments);
// SH}
if (problemMethod != null) {
- methodSubstitute = null;
return problemMethod;
}
infCtx18.solutionsPerTargetType.put(expectedType, new Solution(methodSubstitute, result));
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index 587f586..f3ab7fd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -1663,7 +1663,7 @@
try {
ReferenceBinding[] refs = new ReferenceBinding[glb.length];
System.arraycopy(glb, 0, refs, 0, glb.length); // TODO: if an array type plus more types get here, we get ArrayStoreException!
- types[i] = new IntersectionCastTypeBinding(refs, this.environment);
+ types[i] = this.environment.createIntersectionCastType(refs);
} catch (ArrayStoreException ase) {
scope.problemReporter().genericInferenceError("Cannot compute glb of "+Arrays.toString(glb), null); //$NON-NLS-1$
return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
index a97fa32..810a7b6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
@@ -206,6 +206,11 @@
this.arguments = typeArguments;
}
+ @Override
+ public ParameterizedTypeBinding capture(Scope scope, int position) {
+ return this;
+ }
+
@Override
public TypeBinding uncapture(Scope scope) {
return this;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index 76df96a..2e82bf9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -785,20 +785,20 @@
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=330435, inference should kick in only at source 1.5+
if (typeVariables != Binding.NO_TYPE_VARIABLES && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5) { // generic method
TypeBinding[] newArgs = null;
- for (int i = 0; i < argLength; i++) {
- TypeBinding param = i < paramLength ? parameters[i] : parameters[paramLength - 1];
- if (arguments[i].isBaseType() != param.isBaseType()) {
- if (newArgs == null) {
- newArgs = new TypeBinding[argLength];
- System.arraycopy(arguments, 0, newArgs, 0, argLength);
+ if (compilerOptions.sourceLevel < ClassFileConstants.JDK1_8 || genericTypeArguments != null) { // for 1.8+ inferred calls, we do this inside PGMB.cCM18.
+ for (int i = 0; i < argLength; i++) {
+ TypeBinding param = i < paramLength ? parameters[i] : parameters[paramLength - 1];
+ if (arguments[i].isBaseType() != param.isBaseType()) {
+ if (newArgs == null) {
+ newArgs = new TypeBinding[argLength];
+ System.arraycopy(arguments, 0, newArgs, 0, argLength);
+ }
+ newArgs[i] = environment().computeBoxingType(arguments[i]);
}
- newArgs[i] = environment().computeBoxingType(arguments[i]);
}
}
if (newArgs != null)
arguments = newArgs;
- else // ensure that computeCompatibleMethod() below can update arguments without harming our caller: (TODO: always copy before the loop? only in 1.8?)
- System.arraycopy(arguments, 0, arguments=new TypeBinding[argLength], 0, argLength);
method = ParameterizedGenericMethodBinding.computeCompatibleMethod(method, arguments, this, invocationSite);
if (method == null) return null; // incompatible
if (!method.isValidBinding()) return method; // bound check issue is taking precedence
@@ -4635,7 +4635,7 @@
try {
// orig:
for (int i = 0; i < visibleSize; i++) {
- if ((compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes)) != NOT_COMPATIBLE) {
+ if ((compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes, invocationSite)) != NOT_COMPATIBLE) {
if (i != compatibleCount) {
visible[compatibleCount] = visible[i];
compatibilityLevels[compatibleCount] = compatibilityLevels[i];
@@ -4675,7 +4675,6 @@
int levelj = compatibilityLevels[j];
nextK: for (int k = 0; k < visibleSize; k++) {
if (j == k) continue;
- // TODO do we want to check existing inference contexts whether they can tell us better about the used inferenceKind?
int levelk = compatibilityLevels[k];
if (levelj > -1 && levelk > -1 && levelj != levelk) {
if (levelj < levelk)
@@ -4998,6 +4997,51 @@
} while (scope != null);
return lastMethodScope; // may answer null if no method around
}
+
+ // Version that just answers based on inference kind (at 1.8+) when available.
+ public int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] arguments, InvocationSite site) {
+ if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8 && method instanceof ParameterizedGenericMethodBinding) {
+ int inferenceKind = InferenceContext18.CHECK_UNKNOWN;
+ InferenceContext18 context = null;
+ if (site instanceof Invocation) {
+ Invocation invocation = (Invocation) site;
+ context = invocation.getInferenceContext((ParameterizedGenericMethodBinding) method);
+ if (context != null)
+ inferenceKind = context.inferenceKind;
+ } else if (site instanceof ReferenceExpression) {
+ inferenceKind = ((ReferenceExpression) site).inferenceKind;
+ }
+ /* 1.8+ Post inference compatibility check policy: For non-functional-type arguments, trust inference. For functional type arguments apply compatibility checks as inference
+ engine may not have checked arguments that are not pertinent to applicability. One complication to deal with is when the generic method's parameter is its own type variable
+ and only applicability was inferred and applicability inference instantiated it with jlO due to lack of upper bounds in the bound set.
+ */
+ if (site instanceof Invocation && context != null) { // this block can be readily seen to be not relevant for reference expressions
+ MethodBinding shallowOriginal = method.shallowOriginal();
+ for (int i = 0, length = arguments.length; i < length; i++) {
+ TypeBinding argument = arguments[i];
+ if (!argument.isFunctionalType())
+ continue;
+ TypeBinding parameter = InferenceContext18.getParameter(method.parameters, i, context.isVarArgs());
+ if (argument.isCompatibleWith(parameter, this))
+ continue;
+ TypeBinding shallowParameter = InferenceContext18.getParameter(shallowOriginal.parameters, i, context.isVarArgs());
+ if (shallowParameter.isPertinentToApplicability(argument, shallowOriginal))
+ return NOT_COMPATIBLE;
+ }
+ }
+ switch (inferenceKind) {
+ case InferenceContext18.CHECK_STRICT:
+ return COMPATIBLE;
+ case InferenceContext18.CHECK_LOOSE:
+ return AUTOBOX_COMPATIBLE;
+ case InferenceContext18.CHECK_VARARG:
+ return VARARGS_COMPATIBLE;
+ default:
+ break;
+ }
+ }
+ return parameterCompatibilityLevel(method, arguments, false);
+ }
public int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] arguments) {
return parameterCompatibilityLevel(method, arguments, false);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
index 93849cd..38ee5be 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
@@ -29,13 +29,20 @@
this.enclosingType = enclosingType;
}
- /** Apply the given type arguments on the (declaring class of the) actual constructor being represented by this factory method. */
- public ParameterizedMethodBinding applyTypeArgumentsOnConstructor(TypeBinding[] typeArguments) {
+ public MethodBinding getConstructor() {
+ return this.staticFactoryFor;
+ }
+
+ /** Apply the given type arguments on the (declaring class of the) actual constructor being represented by this factory method and
+ if method type arguments is not empty materialize the parameterized generic constructor
+ */
+ public ParameterizedMethodBinding applyTypeArgumentsOnConstructor(TypeBinding[] typeArguments, TypeBinding[] constructorTypeArguments) {
ReferenceBinding parameterizedType = this.environment.createParameterizedType(this.declaringClass, typeArguments,
this.enclosingType);
for (MethodBinding parameterizedMethod : parameterizedType.methods()) {
if (parameterizedMethod.original() == this.staticFactoryFor)
- return (ParameterizedMethodBinding) parameterizedMethod;
+ return constructorTypeArguments.length > 0 ? this.environment.createParameterizedGenericMethod(parameterizedMethod, constructorTypeArguments) :
+ (ParameterizedMethodBinding) parameterizedMethod;
if (parameterizedMethod instanceof ProblemMethodBinding) {
MethodBinding closestMatch = ((ProblemMethodBinding)parameterizedMethod).closestMatch;
if (closestMatch instanceof ParameterizedMethodBinding && closestMatch.original() == this.staticFactoryFor)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
index ad01d14..597e2d6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -454,6 +454,16 @@
}
}
}
+ break;
+ case Binding.INTERSECTION_CAST_TYPE:
+ IntersectionCastTypeBinding ictb = (IntersectionCastTypeBinding) this;
+ ReferenceBinding[] intersectingTypes = ictb.getIntersectingTypes();
+ for (int i = 0, length = intersectingTypes.length; i < length; i++) {
+ TypeBinding superType = intersectingTypes[i].findSuperTypeOriginatingFrom(otherType);
+ if (superType != null)
+ return superType;
+ }
+ break;
}
return null;
}
@@ -639,6 +649,27 @@
// version that allows to capture a type bound using 'scope':
public abstract boolean isCompatibleWith(TypeBinding right, /*@Nullable*/ Scope scope);
+/* Answer true if the receiver type can be assigned to the argument type (right) with boxing/unboxing applied.
+ */
+public boolean isBoxingCompatibleWith(TypeBinding right, /*@NonNull */ Scope scope) {
+
+ if (right == null)
+ return false;
+
+ if (TypeBinding.equalsEquals(this, right))
+ return true;
+
+ if (this.isCompatibleWith(right, scope))
+ return true;
+
+ if (this.isBaseType() != right.isBaseType()) {
+ TypeBinding convertedType = scope.environment().computeBoxingType(this);
+ if (TypeBinding.equalsEquals(convertedType, right) || convertedType.isCompatibleWith(right, scope))
+ return true;
+ }
+ return false;
+}
+
public boolean isEnum() {
return false;
}
@@ -1299,6 +1330,12 @@
TypeBinding otherBound = otherWildcard.bound;
switch (otherWildcard.boundKind) {
case Wildcard.EXTENDS:
+ if (otherBound instanceof IntersectionCastTypeBinding) {
+ TypeBinding [] intersectingTypes = ((IntersectionCastTypeBinding) otherBound).intersectingTypes;
+ for (int i = 0, length = intersectingTypes.length; i < length; i++)
+ if (TypeBinding.equalsEquals(intersectingTypes[i], this))
+ return true;
+ }
if (TypeBinding.equalsEquals(otherBound, this))
return true; // ? extends T <= ? extends ? extends T
if (upperBound == null)
@@ -1311,6 +1348,12 @@
return upperBound.isCompatibleWith(otherBound);
case Wildcard.SUPER:
+ if (otherBound instanceof IntersectionCastTypeBinding) {
+ TypeBinding [] intersectingTypes = ((IntersectionCastTypeBinding) otherBound).intersectingTypes;
+ for (int i = 0, length = intersectingTypes.length; i < length; i++)
+ if (TypeBinding.equalsEquals(intersectingTypes[i], this))
+ return true;
+ }
if (TypeBinding.equalsEquals(otherBound, this))
return true; // ? super T <= ? super ? super T
if (lowerBound == null)
@@ -1574,6 +1617,11 @@
}
}
+// return a name that can be passed to Signature.createTypeSignature
+public char [] signableName() {
+ return readableName();
+}
+
/**
* Answer the receiver classfile signature.
* Arrays & base types do not distinguish between signature() & constantPoolName().
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
index e9641f9..c9611a2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -65,6 +65,7 @@
char[] WILDCARD_PLUS = { '+' };
char[] WILDCARD_CAPTURE_NAME_PREFIX = "capture#".toCharArray(); //$NON-NLS-1$
char[] WILDCARD_CAPTURE_NAME_SUFFIX = "-of ".toCharArray(); //$NON-NLS-1$
+ char[] WILDCARD_CAPTURE_SIGNABLE_NAME_SUFFIX = "capture-of ".toCharArray(); //$NON-NLS-1$
char[] WILDCARD_CAPTURE = { '!' };
char[] CAPTURE18 = { '^' };
char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
index d59dd78..634c53b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
@@ -134,7 +134,7 @@
} catch (ArrayStoreException ase) {
return this.bound;
}
- return new IntersectionCastTypeBinding(allBounds, this.environment);
+ return this.environment.createIntersectionCastType(allBounds);
}
public ReferenceBinding actualType() {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java
index f242409..18ba5a6 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -20,7 +20,7 @@
* <pre>
* SwitchStatement:
* <b>switch</b> <b>(</b> Expression <b>)</b>
- * <b>{</b> { SwitchCase | Statement } } <b>}</b>
+ * <b>{</b> { SwitchCase | Statement } <b>}</b>
* SwitchCase:
* <b>case</b> Expression <b>:</b>
* <b>default</b> <b>:</b>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
index 62c4524..ef9f802 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
@@ -476,7 +476,7 @@
local.declarationSourceEnd,
local.sourceStart,
local.sourceEnd,
- local.type == null ? Signature.createTypeSignature(binding.type.readableName(), true) : Util.typeSignature(local.type),
+ local.type == null ? Signature.createTypeSignature(binding.type.signableName(), true) : Util.typeSignature(local.type),
local.annotations,
local.modifiers,
local.getKind() == AbstractVariableDeclaration.PARAMETER);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
index ac15327..0c7835e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -17,10 +17,12 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.zip.ZipFile;
@@ -1045,6 +1047,102 @@
}
return null;
}
+
+private List<String> getInverseFullName(char[] qualifier, char[] simpleName) {
+ List <String> result = new ArrayList<String>();
+ if (qualifier != null && qualifier.length > 0) {
+ result.addAll(Arrays.asList(new String(qualifier).split("\\.")));//$NON-NLS-1$
+ Collections.reverse(result);
+ }
+ if (simpleName != null) result.add(0, new String(simpleName));
+ return result;
+}
+
+/** returns the row index which has the highest column entry.
+ * TODO: rewrite this code with list when (if) we move to 1.8 [with FP constructs].
+ */
+private int getMaxResult(int[][] resultsMap) {
+ int rows = resultsMap.length;
+ int cols = resultsMap[0].length;
+ List <Integer> candidates = new ArrayList<Integer>();
+ candidates.add(0); //default row
+
+ for (int j = 0; j < cols; ++j) {
+ int current = resultsMap[0][j];
+ for (int i = 1; i < rows; ++i) {
+ int tmp = resultsMap[i][j];
+ if (tmp < current) continue;
+ if (tmp > current) {
+ current = tmp;
+ candidates.clear();
+ }
+ candidates.add(i);// there is atleast one element always.
+ }
+ if (candidates.size() <= 1) break; // found
+ }
+ return candidates.get(0);
+}
+
+/** apply the function to map the parameter full name to an index
+ */
+private int mapParameter(List <String> patternParameterFullName, List <String> methodParameterFullName) {
+ int patternLen = patternParameterFullName.size();
+ int methodLen = methodParameterFullName.size();
+ int size = patternLen < methodLen ? patternLen : methodLen;
+ int result = -1;
+ for (int i = 0; i < size; i++) {
+ if (!patternParameterFullName.get(i).equals(methodParameterFullName.get(i))) break;
+ ++result;
+ }
+ return patternLen == methodLen && result + 1 == patternLen ? Integer.MAX_VALUE : result;
+}
+/**
+ * returns an array of integers whose elements are matching indices.
+ * As a special case, full match would have max value as the index.
+ */
+private int[] getResultMap(Map<Integer, List<String>> patternMap, Map<Integer, List<String>> methodMap) {
+ int paramLength = methodMap.size();
+ int[] result = new int[paramLength];
+ for (int p = 0; p < paramLength; p++) {
+ result[p] = mapParameter(patternMap.get(p), methodMap.get(p));
+ }
+ return result;
+}
+
+private Map<Integer, List<String>> getSplitNames(char[][] qualifiedNames, char[][] simpleNames) {
+ int paramLength = simpleNames.length;
+ Map <Integer, List<String>> result = new HashMap<Integer, List<String>>();
+ for (int p = 0; p < paramLength; p++) result.put(p, getInverseFullName(qualifiedNames[p], simpleNames[p]));
+ return result;
+}
+
+private Map<Integer, List<String>> getSplitNames(MethodBinding method) {
+ TypeBinding[] methodParameters = method.parameters;
+ int paramLength = methodParameters == null ? 0 : methodParameters.length;
+ Map <Integer, List<String>> result = new HashMap<Integer, List<String>>();
+ for (int p = 0; p < paramLength; p++) result.put(p, getInverseFullName(methodParameters[p].qualifiedSourceName(), null)); // source is part of qualifiedSourceName here);
+ return result;
+}
+
+/**
+ * Selects the most applicable method (though similar but not to be confused with its namesake in jls)
+ * All this machinery for that elusive uncommon case referred in bug 431357.
+ */
+private MethodBinding getMostApplicableMethod(List<MethodBinding> possibleMethods) {
+ int size = possibleMethods.size();
+ MethodBinding result = size != 0 ? possibleMethods.get(0) : null;
+ if (size > 1) {
+ MethodPattern methodPattern = ((MethodPattern) this.pattern);
+ // can cache but may not be worth since this is not a common case
+ Map<Integer, List<String>> methodPatternReverseNames = getSplitNames(methodPattern.parameterQualifications, methodPattern.parameterSimpleNames);
+ int len = possibleMethods.size();
+ int[][] resultMaps = new int[len][];
+ for (int i = 0; i < len; ++i) resultMaps[i] = getResultMap(methodPatternReverseNames, getSplitNames(possibleMethods.get(i)));
+ result = possibleMethods.get(getMaxResult(resultMaps));
+ }
+ return result;
+}
+
private MethodBinding getMethodBinding0(MethodPattern methodPattern) {
if (this.unitScope == null) return null;
// Try to get binding from cache
@@ -1061,6 +1159,7 @@
typeName = methodPattern.declaringType.getFullyQualifiedName().toCharArray();
}
TypeBinding declaringTypeBinding = getType(typeName, typeName);
+ MethodBinding result = null;
if (declaringTypeBinding != null) {
if (declaringTypeBinding.isArrayType()) {
declaringTypeBinding = declaringTypeBinding.leafComponentType();
@@ -1074,6 +1173,7 @@
int methodsLength = methods.length;
TypeVariableBinding[] refTypeVariables = referenceBinding.typeVariables();
int typeVarLength = refTypeVariables==null ? 0 : refTypeVariables.length;
+ List <MethodBinding> possibleMethods = new ArrayList<MethodBinding>(methodsLength);
for (int i=0; i<methodsLength; i++) {
TypeBinding[] methodParameters = methods[i].parameters;
int paramLength = methodParameters==null ? 0 : methodParameters.length;
@@ -1111,14 +1211,14 @@
}
}
if (found) {
- this.bindings.put(methodPattern, methods[i]);
- return methods[i];
+ possibleMethods.add(methods[i]);
}
}
+ result = getMostApplicableMethod(possibleMethods);
}
}
- this.bindings.put(methodPattern, new ProblemMethodBinding(methodPattern.selector, null, ProblemReasons.NotFound));
- return null;
+ this.bindings.put(methodPattern, result != null ? result : new ProblemMethodBinding(methodPattern.selector, null, ProblemReasons.NotFound));
+ return result;
}
protected boolean hasAlreadyDefinedType(CompilationUnitDeclaration parsedUnit) {
CompilationResult result = parsedUnit.compilationResult;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
index 5830863..5aed30a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
@@ -217,7 +217,7 @@
&& !(messageSend instanceof TSuperMessageSend) // similar to "super" but for codegen it's a "this"
//jsv}
&& !messageSend.isSuperAccess()
- && !(method.isDefault() && this.pattern.focus != null
+ && !(method.isDefault() && this.pattern.focus != null
&& !CharOperation.equals(this.pattern.declaringPackageName, method.declaringClass.qualifiedPackageName()));
}
public int match(ASTNode node, MatchingNodeSet nodeSet) {
@@ -437,6 +437,8 @@
return INACCURATE_MATCH;
}
boolean foundTypeVariable = false;
+ MethodBinding focusMethodBinding = null;
+ boolean checkedFocus = false;
// verify each parameter
for (int i = 0; i < parameterCount; i++) {
//{ObjectTeams: callin method?
@@ -446,11 +448,19 @@
TypeBinding argType = methodParamters[i];
// SH}
int newLevel = IMPOSSIBLE_MATCH;
- if (argType.isMemberType()) {
- // only compare source name for member type (bug 41018)
- newLevel = CharOperation.match(this.pattern.parameterSimpleNames[i], argType.sourceName(), this.isCaseSensitive)
- ? ACCURATE_MATCH
- : IMPOSSIBLE_MATCH;
+ boolean foundLevel = false;
+ if (argType.isMemberType() || this.pattern.parameterQualifications[i] != null) {
+ if (!checkedFocus) {
+ focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
+ checkedFocus = true;
+ }
+ if (focusMethodBinding != null) {// textual comparison insufficient
+ TypeBinding[] parameters = focusMethodBinding.parameters;
+ if (parameters.length >= parameterCount) {
+ newLevel = argType.isEquivalentTo((parameters[i])) ? ACCURATE_MATCH : IMPOSSIBLE_MATCH;
+ foundLevel = true;
+ }
+ }
} else {
// TODO (frederic) use this call to refine accuracy on parameter types
// newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], this.pattern.parametersTypeArguments[i], 0, argType);
@@ -461,7 +471,9 @@
if (skipImpossibleArg) {
// Do not consider match as impossible while finding declarations and source level >= 1.5
// (see bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
- newLevel = level;
+ if (!foundLevel) {
+ newLevel = level;
+ }
} else if (argType.isTypeVariable()) {
newLevel = level;
foundTypeVariable = true;
@@ -475,7 +487,8 @@
if (foundTypeVariable) {
if (!method.isStatic() && !method.isPrivate()) {
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836, No point in textually comparing type variables, captures etc with concrete types.
- MethodBinding focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
+ if (!checkedFocus)
+ focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
if (focusMethodBinding != null) {
if (matchOverriddenMethod(focusMethodBinding.declaringClass, focusMethodBinding, method)) {
return ACCURATE_MATCH;
@@ -982,7 +995,7 @@
} else {
//{ObjectTeams: try harder to use a declaring qualification to lock down to this exact role:
/* orig:
- declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, method.declaringClass);
+ declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, method.declaringClass);
:giro */
char[] patternDeclaringQualification = this.pattern.getDeclaringQualification();
ReferenceBinding declaringClass = method.declaringClass;