update jdt.core to I20211025-1800
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/CharDeduplicationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/CharDeduplicationTest.java
new file mode 100644
index 0000000..92fa0a2
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/CharDeduplicationTest.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2021 jkubitz and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * jkubitz - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.compiler;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+
+import org.eclipse.jdt.core.tests.junit.extension.TestCase;
+import org.eclipse.jdt.internal.compiler.util.CharDeduplication;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class CharDeduplicationTest extends TestCase {
+
+ public CharDeduplicationTest(String testName) {
+ super(testName);
+ }
+
+ public static Test suite() {
+
+ TestSuite suite = new TestSuite(CharDeduplicationTest.class.getPackageName());
+ suite.addTest(new TestSuite(CharDeduplicationTest.class));
+ return suite;
+ }
+
+ public void testDeduplication() {
+ for (int i = 0; i < 3; i++) {
+ assertDeduplication("a");
+ // ..
+ assertDeduplication("z");
+
+ assertDeduplication("12");
+ assertDeduplication("123");
+ assertDeduplication("1234");
+ assertDeduplication("12345");
+ assertDeduplication("123456");
+ assertNoDeduplication("1234567");
+
+ // new:
+ assertDeduplication("0"); // illegal identifier - but who cares.
+ assertDeduplication("A"); // why not?
+ assertDeduplication("$"); // legal
+ assertDeduplication("_"); // note that "_" may become more common after JEP 302 as keyword for unused
+ // lambda parameter!
+ assertDeduplication("" + (char) 0);
+ // ..
+ assertDeduplication("" + (char) 127);
+ assertNoDeduplication("" + (char) 128); // non-Ascii
+ }
+ }
+
+ public void testDeduplicationMid() {
+ String text = "abcdefghijklmn";
+ for (int start = 0; start < text.length(); start++) {
+ for (int end = start; end < text.length(); end++) {
+ assertDedup(text, (end - start) <= CharDeduplication.OPTIMIZED_LENGTH, start, end);
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testDeduplicationTableSize() {
+ CharDeduplication deduplication = CharDeduplication.getThreadLocalInstance();
+ deduplication.reset();// to test the overflow we need to start empty
+ for (int overload = 0; overload < 3; overload++) {
+ HashMap<Integer, char[]> expecteds = new HashMap<>();
+ for (int i = 0; i < CharDeduplication.TABLE_SIZE + overload; i++) {
+ int numberWithFixedLength = 10000 + i;
+ String string = "" + numberWithFixedLength;
+ char[] a = string.toCharArray();
+ char[] expected = deduplication.sharedCopyOfRange(a, 0, a.length);
+ expecteds.put(i, expected);
+ }
+ for (int t = 0; t < 2; t++) {
+ for (int i = 0; i < expecteds.size(); i++) {
+ char[] expected = expecteds.get(i);
+ char[] other = String.valueOf(expected).toCharArray();
+ if (overload == 0 || i > 0) {
+ assertDedup(true, 0, expected.length, expected, other);
+ } else {
+ // situation after table overflow:
+ char[] actual = deduplication.sharedCopyOfRange(other, 0, expected.length);
+ // both actual == expected or actual != expected may happen
+ // but we can assert that the next deduplication works again:
+ char[] other2 = String.valueOf(expected).toCharArray();
+ assertDedup(true, 0, expected.length, actual, other2);
+ }
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ CharDeduplicationTest test=new CharDeduplicationTest("");
+ System.out.println("min= ~"+ LongStream.range(0, 100).map(t->test.runPerformanceTest()).min());
+ // min= ~0.36sec
+ }
+
+ public long runPerformanceTest() {
+ long nanoTime = System.nanoTime();
+ CharDeduplication deduplication = CharDeduplication.getThreadLocalInstance();
+ for (int j = 0; j < 100; j++) {
+ for (int i = 0; i < 100_000; i++) {
+ String hexString = Integer.toHexString(i);
+ char[] chars = hexString.toCharArray();
+ deduplication.sharedCopyOfRange(chars, 0, chars.length);
+ }
+ }
+ long nanoTime2 = System.nanoTime();
+ long durationNanos = nanoTime2 - nanoTime;
+ System.out.println(durationNanos);
+ return durationNanos;
+ }
+
+ public void testAll() {
+ testDeduplication();
+ testDeduplicationMid();
+ testDeduplicationTableSize();
+ }
+
+ public void testMultithreaded() throws Exception {
+ int nThreads = 8;
+ List<FutureTask<Object>> tasks = IntStream.range(0, nThreads * 2).mapToObj(i -> new FutureTask<Object>(() -> {
+ testAll();
+ return null;
+ })).collect(Collectors.toList());
+ ExecutorService executor = Executors.newFixedThreadPool(nThreads);
+ tasks.forEach(executor::submit);
+ for (FutureTask<Object> task : tasks) {
+ try {
+ task.get();
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+ executor.shutdownNow();
+ }
+
+ private void assertDeduplication(String string) {
+ assertDedup(string, true, 0, string.length());
+ }
+
+ private void assertNoDeduplication(String string) {
+ assertDedup(string, false, 0, string.length());
+ }
+
+ private void assertDedup(String string, boolean same, int startPosition, int end) {
+ char[] a = string.toCharArray();
+ char[] b = string.toCharArray();
+ assertNotSame(a, b);
+ CharDeduplication deduplication = CharDeduplication.getThreadLocalInstance();
+ char[] expected = deduplication.sharedCopyOfRange(a, startPosition, end);
+ assertDedup(same, startPosition, end, expected, b);
+ }
+
+ private char[] assertDedup(boolean same, int startPosition, int end, char[] expected, char[] other) {
+ assertNotSame(expected, other);
+ CharDeduplication deduplication = CharDeduplication.getThreadLocalInstance();
+ char[] actual = deduplication.sharedCopyOfRange(other, startPosition, end);
+ String state = "expected=" + String.valueOf(expected) + ", actual=" + String.valueOf(actual);
+ if (same) {
+ assertSame(state, expected, actual);
+ } else {
+ assertNotSame("Expected different instances. But thats not a requirement but an implementation detail test:"
+ + state, expected, actual);
+ }
+ return actual;
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/AllocationExpressionCompletionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/AllocationExpressionCompletionTest.java
index 847f772..3069443 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/AllocationExpressionCompletionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/AllocationExpressionCompletionTest.java
@@ -28,7 +28,40 @@
/*
* Completion inside an if statement.
*/
-public void testInIfStatement() {
+public void testInIfStatement1() {
+ this.runTestCheckMethodParse(
+ // compilationUnit:
+ "class Bar { \n" +
+ " void foo() { \n" +
+ " if (true) { \n" +
+ " new z.y.X(1, 2, i); \n" +
+ " } \n" +
+ " } \n" +
+ "}\n",
+ // completeBehind:
+ "X(",
+ // expectedCompletionNodeToString:
+ "<CompleteOnAllocationExpression:new z.y.X(<CompleteOnName:>, 2, i)>",
+ // expectedUnitDisplayString:
+ "class Bar {\n" +
+ " Bar() {\n" +
+ " }\n" +
+ " void foo() {\n" +
+ " if (true)\n" +
+ " {\n" +
+ " <CompleteOnAllocationExpression:new z.y.X(<CompleteOnName:>, 2, i)>;\n" +
+ " }\n" +
+ " }\n" +
+ "}\n",
+ // expectedCompletionIdentifier:
+ "",
+ // expectedReplacedSource:
+ "new z.y.X(1, 2, i)",
+ // test name
+ "<complete inside an if statement>"
+ );
+}
+public void testInIfStatement2() {
this.runTestCheckMethodParse(
// compilationUnit:
"class Bar { \n" +
@@ -41,15 +74,16 @@
// completeBehind:
"X(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnAllocationExpression:new z.y.X(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
- " {\n" +
- " <CompleteOnAllocationExpression:new z.y.X(1, 2)>;\n" +
- " }\n" +
+ " if (true)\n" +
+ " {\n" +
+ " new z.y.X(1, 2, <CompleteOnName:>, i);\n" +
+ " }\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
@@ -66,7 +100,35 @@
* ie. ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
* where ClassType is a qualified type name
*/
-public void testNoQualificationQualifiedTypeName() {
+public void testNoQualificationQualifiedTypeName1() {
+ this.runTestCheckMethodParse(
+ // compilationUnit:
+ "class Bar { \n" +
+ " void foo() { \n" +
+ " new z.y.X(1, 2, i); \n" +
+ " } \n" +
+ "}\n",
+ // completeBehind:
+ "X(",
+ // expectedCompletionNodeToString:
+ "<CompleteOnAllocationExpression:new z.y.X()>",
+ // expectedUnitDisplayString:
+ "class Bar {\n" +
+ " Bar() {\n" +
+ " }\n" +
+ " void foo() {\n" +
+ " <CompleteOnAllocationExpression:new z.y.X()>;\n" +
+ " }\n" +
+ "}\n",
+ // expectedCompletionIdentifier:
+ "",
+ // expectedReplacedSource:
+ "",
+ // test name
+ "<complete on non qualified instance creation with qualified type name>"
+ );
+}
+public void testNoQualificationQualifiedTypeName2() {
this.runTestCheckMethodParse(
// compilationUnit:
"class Bar { \n" +
@@ -77,13 +139,13 @@
// completeBehind:
"X(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnAllocationExpression:new z.y.X(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
- " <CompleteOnAllocationExpression:new z.y.X(1, 2)>;\n" +
+ " new z.y.X(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
@@ -100,7 +162,35 @@
* ie. ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
* where ClassType is a simple type name
*/
-public void testNoQualificationSimpleTypeName() {
+public void testNoQualificationSimpleTypeName1() {
+ this.runTestCheckMethodParse(
+ // compilationUnit:
+ "class Bar { \n" +
+ " void foo() { \n" +
+ " new X(1, 2, i); \n" +
+ " } \n" +
+ "}\n",
+ // completeBehind:
+ "X(",
+ // expectedCompletionNodeToString:
+ "<CompleteOnAllocationExpression:new X()>",
+ // expectedUnitDisplayString:
+ "class Bar {\n" +
+ " Bar() {\n" +
+ " }\n" +
+ " void foo() {\n" +
+ " <CompleteOnAllocationExpression:new X()>;\n" +
+ " }\n" +
+ "}\n",
+ // expectedCompletionIdentifier:
+ "",
+ // expectedReplacedSource:
+ "",
+ // test name
+ "<complete on non qualified instance creation with simple type name>"
+ );
+}
+public void testNoQualificationSimpleTypeName2() {
this.runTestCheckMethodParse(
// compilationUnit:
"class Bar { \n" +
@@ -111,13 +201,13 @@
// completeBehind:
"X(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnAllocationExpression:new X(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
- " <CompleteOnAllocationExpression:new X(1, 2)>;\n" +
+ " new X(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
@@ -133,7 +223,35 @@
*
* ie. ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
*/
-public void testQualifiedWithName() {
+public void testQualifiedWithName1() {
+ this.runTestCheckMethodParse(
+ // compilationUnit:
+ "class Bar {\n" +
+ " void foo() { \n" +
+ " Buz.x.new X(1, 2, i); \n" +
+ " } \n" +
+ "}\n",
+ // completeBehind:
+ "X(",
+ // expectedCompletionNodeToString:
+ "<CompleteOnQualifiedAllocationExpression:Buz.x.new X(<CompleteOnName:>, 2, i)>",
+ // expectedUnitDisplayString:
+ "class Bar {\n" +
+ " Bar() {\n" +
+ " }\n" +
+ " void foo() {\n" +
+ " <CompleteOnQualifiedAllocationExpression:Buz.x.new X(<CompleteOnName:>, 2, i)>;\n" +
+ " }\n" +
+ "}\n",
+ // expectedCompletionIdentifier:
+ "",
+ // expectedReplacedSource:
+ "Buz.x.new X(1, 2, i)",
+ // test name
+ "<complete on name qualified instance creation>"
+ );
+}
+public void testQualifiedWithName2() {
this.runTestCheckMethodParse(
// compilationUnit:
"class Bar {\n" +
@@ -144,13 +262,13 @@
// completeBehind:
"X(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnQualifiedAllocationExpression:Buz.x.new X(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
- " <CompleteOnQualifiedAllocationExpression:Buz.x.new X(1, 2)>;\n" +
+ " Buz.x.new X(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
@@ -166,7 +284,35 @@
*
* ie. ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
*/
-public void testQualifiedWithPrimary() {
+public void testQualifiedWithPrimary1() {
+ this.runTestCheckMethodParse(
+ // compilationUnit:
+ "class Bar { \n" +
+ " void foo() { \n" +
+ " primary().new X(1, 2, i); \n" +
+ " } \n" +
+ "}\n",
+ // completeBehind:
+ "X(",
+ // expectedCompletionNodeToString:
+ "<CompleteOnQualifiedAllocationExpression:primary().new X(<CompleteOnName:>, 2, i)>",
+ // expectedUnitDisplayString:
+ "class Bar {\n" +
+ " Bar() {\n" +
+ " }\n" +
+ " void foo() {\n" +
+ " <CompleteOnQualifiedAllocationExpression:primary().new X(<CompleteOnName:>, 2, i)>;\n" +
+ " }\n" +
+ "}\n",
+ // expectedCompletionIdentifier:
+ "",
+ // expectedReplacedSource:
+ "primary().new X(1, 2, i)",
+ // test name
+ "<complete on primary qualified instance creation>"
+ );
+}
+public void testQualifiedWithPrimary2() {
this.runTestCheckMethodParse(
// compilationUnit:
"class Bar { \n" +
@@ -177,13 +323,13 @@
// completeBehind:
"X(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnQualifiedAllocationExpression:primary().new X(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
- " <CompleteOnQualifiedAllocationExpression:primary().new X(1, 2)>;\n" +
+ " primary().new X(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ExplicitConstructorInvocationCompletionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ExplicitConstructorInvocationCompletionTest.java
index c0a0849..2d89e67 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ExplicitConstructorInvocationCompletionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ExplicitConstructorInvocationCompletionTest.java
@@ -49,7 +49,7 @@
// completeBehind:
"super(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnExplicitConstructorCall:primary().super(1, 2)>;",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" public class InnerBar {\n" +
@@ -58,7 +58,7 @@
" }\n" +
" public class SubInnerBar extends InnerBar {\n" +
" SubInnerBar(Bar x) {\n" +
- " <CompleteOnExplicitConstructorCall:primary().super(1, 2)>;\n" +
+ " primary().super(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
" }\n" +
" static Bar x;\n" +
@@ -98,7 +98,7 @@
// completeBehind:
"this(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnExplicitConstructorCall:primary().this(1, 2)>;",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" public class InnerBar {\n" +
@@ -107,7 +107,7 @@
" }\n" +
" public class SubInnerBar extends InnerBar {\n" +
" SubInnerBar(Bar x) {\n" +
- " <CompleteOnExplicitConstructorCall:primary().this(1, 2)>;\n" +
+ " primary().this(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
" }\n" +
" static Bar x;\n" +
@@ -140,11 +140,11 @@
// completeBehind:
"super(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnExplicitConstructorCall:super(1, 2)>;",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
- " <CompleteOnExplicitConstructorCall:super(1, 2)>;\n" +
+ " super(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
@@ -171,11 +171,11 @@
// completeBehind:
"this(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnExplicitConstructorCall:this(1, 2)>;",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
- " <CompleteOnExplicitConstructorCall:this(1, 2)>;\n" +
+ " this(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/MethodInvocationCompletionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/MethodInvocationCompletionTest.java
index 38dca1c..3f061ee 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/MethodInvocationCompletionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/MethodInvocationCompletionTest.java
@@ -395,19 +395,19 @@
// completeBehind:
"fred(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnMessageSend:this.fred(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
- " <CompleteOnMessageSend:this.fred(1, 2)>;\n" +
+ " this.fred(1, 2, <CompleteOnName:>, i);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
"",
// expectedReplacedSource:
- "fred(1, 2,",
+ "",
// test name
"<completion just before last parameter>"
);
@@ -555,19 +555,19 @@
// completeBehind:
"fred(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnMessageSend:bar().fred(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class X {\n" +
" X() {\n" +
" }\n" +
" void foo() {\n" +
- " <CompleteOnMessageSend:bar().fred(1, 2)>;\n" +
+ " label1: bar().fred(1, 2, <CompleteOnName:>, o);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
"",
// expectedReplacedSource:
- "fred(1, 2,",
+ "",
// expectedLabels:
new String[] {"label1"},
// test name
@@ -588,19 +588,19 @@
// completeBehind:
"fred(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnMessageSend:fred(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
- " <CompleteOnMessageSend:fred(1, 2)>;\n" +
+ " label1: fred(1, 2, <CompleteOnName:>, o);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
"",
// expectedReplacedSource:
- "fred(1, 2,",
+ "",
// expectedLabels:
new String[] {"label1"},
// test name
@@ -813,20 +813,20 @@
// completeBehind:
"x.fred(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnMessageSend:x.fred(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
" X x;\n" +
- " <CompleteOnMessageSend:x.fred(1, 2)>;\n" +
+ " x.fred(1, 2, <CompleteOnName:>, o);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
"",
// expectedReplacedSource:
- "fred(1, 2,",
+ "",
// test name
"<completion with name receiver and 2 arguments>"
);
@@ -846,20 +846,20 @@
// completeBehind:
"x.fred(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnMessageSend:y.x.fred(1, 2)>",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" Bar() {\n" +
" }\n" +
" void foo() {\n" +
" X x;\n" +
- " <CompleteOnMessageSend:y.x.fred(1, 2)>;\n" +
+ " y.x.fred(1, 2, <CompleteOnName:>, o);\n" +
" }\n" +
"}\n",
// expectedCompletionIdentifier:
"",
// expectedReplacedSource:
- "fred(1, 2,",
+ "",
// test name
"<completion with qualified name receiver>"
);
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index 205b936..3de6495 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -1393,6 +1393,7 @@
expectedProblemAttributes.put("EnhancedSwitchMissingDefault", new ProblemAttributes(true));
expectedProblemAttributes.put("DuplicateTotalPattern", new ProblemAttributes(true));
expectedProblemAttributes.put("UnexpectedTypeinSwitchPattern", new ProblemAttributes(true));
+ expectedProblemAttributes.put("ClassExtendFinalRecord", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
StringBuffer failures = new StringBuffer();
StringBuffer correctResult = new StringBuffer(70000);
@@ -3091,6 +3092,7 @@
expectedProblemAttributes.put("EnhancedSwitchMissingDefault", SKIP);
expectedProblemAttributes.put("DuplicateTotalPattern", SKIP);
expectedProblemAttributes.put("UnexpectedTypeinSwitchPattern", SKIP);
+ expectedProblemAttributes.put("ClassExtendFinalRecord", SKIP);
Map constantNamesIndex = new HashMap();
Field[] fields = JavaCore.class.getFields();
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 bf28ff2..0a85da8 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2020 GK Software AG, and others.
+ * Copyright (c) 2013, 2021 GK Software SE, and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10325,4 +10325,40 @@
"}\n"
});
}
+ public void testBug576516() {
+ if (this.complianceLevel < ClassFileConstants.JDK11) return; // uses 'var'
+ runConformTest(
+ new String[] {
+ "lib/Base.java",
+ "package lib;\n" +
+ "public class Base {}\n",
+
+ "lib/ClassA.java",
+ "package lib;\n" +
+ "import lib.Holder.Tagging;\n" +
+ "public class ClassA extends Base implements Tagging { }\n",
+
+ "lib/ClassB.java",
+ "package lib;\n" +
+ "import lib.Holder.Tagging;\n" +
+ "public class ClassB extends Base implements Tagging { }\n",
+
+ "lib/Holder.java",
+ "package lib;\n" +
+ "public class Holder {\n" +
+ " interface Tagging { }\n" +
+ "}",
+
+ "Test.java",
+ "import java.util.stream.Stream;\n" +
+ "import lib.ClassA;\n" +
+ "import lib.ClassB;\n" +
+ "public class Test {\n" +
+ "\n" +
+ " public static void main(String[] args) {\n" +
+ " var builders = Stream.of(new ClassA(), new ClassB());\n" +
+ " }\n" +
+ "}\n"
+ });
+ }
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
index bffc9f2..c7cf6b1 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
@@ -1046,7 +1046,10 @@
" try {\n" +
" X x = (X & I & J) o;\n" +
" } catch (ClassCastException e) {\n" +
- " System.out.println(e.getMessage());\n" +
+ // Make assertion more robust by producing predictable output for Java 11+:
+ // - Omit stack trace
+ // - Cut off class loader name (e.g. 'java.net.URLClassLoader @f3f9f4b') for easier matching
+ " System.out.println(e.getMessage().replaceFirst(\"(unnamed module of loader).*\", \"$1\"));\n" +
" }\n" +
" }\n" +
"}\n",
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
index 3cf5ff8..c0697c8 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
@@ -14474,7 +14474,10 @@
" try {\n" +
" OtherResult result = demo.test(new OtherResult());\n" +
" } catch (ClassCastException e) {\n" +
- " System.out.println(e.getMessage());\n" + // omit the stack trace for test robustness
+ // Make assertion more robust by producing predictable output for Java 11+:
+ // - Omit stack trace
+ // - Cut off class loader name (e.g. 'java.net.URLClassLoader @f3f9f4b') for easier matching
+ " System.out.println(e.getMessage().replaceFirst(\"(unnamed module of loader).*\", \"$1\"));\n" +
" }\n" +
" }\n" +
"}\n"
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java
index ec57d5f..902493a 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordsRestrictedClassTest.java
@@ -9099,5 +9099,24 @@
},
"0");
}
+public void testBug576519_001() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "class X extends Point{\n"+
+ " public X(int x, int y){\n"+
+ " \n" +
+ " }\n"+
+ "}\n"+
+ "record Point(int x, int y){\n"+
+ "}",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 1)\n" +
+ " class X extends Point{\n" +
+ " ^^^^^\n" +
+ "The record Point cannot be the superclass of X; a record is final and cannot be extended\n" +
+ "----------\n");
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java
index 66d81ff..d35f62f 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java
@@ -2230,17 +2230,19 @@
new String[] {
"X.java",
"public class X {\n"+
- " private static void foo(Object o) {\n"+
+ " public static void foo(Object o) {\n"+
" switch (o) {\n"+
" case null, Integer i -> System.out.println(0);\n"+
" default -> System.out.println(o);\n"+
" }\n"+
+ " }\n"+
+ " public static void bar(Object o) {\n"+
" Zork();\n"+
" }\n"+
"}",
},
"----------\n" +
- "1. ERROR in X.java (at line 7)\n" +
+ "1. ERROR in X.java (at line 9)\n" +
" Zork();\n" +
" ^^^^\n" +
"The method Zork() is undefined for the type X\n" +
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TextBlockTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TextBlockTest.java
index efb0f7f..0c60d32 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TextBlockTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TextBlockTest.java
@@ -1550,4 +1550,36 @@
getCompilerOptions(),
new String[] {"--enable-preview"});
}
+ public void testBug575953() {
+ runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " String TEXT_BLOCK = \"\"\"\n" +
+ " public class A {\n" +
+ " public void foo() {\\s\n" +
+ " String k = \\\"\"\"\n" +
+ " abcdefg\n" +
+ " \\\"\"\"\n" +
+ " System.out.pri\\\n" +
+ " ntln(\"abc\");\\s\n" +
+ " }\n" +
+ " }\\\n" +
+ " \"\"\";\n" +
+ " System.out.println(TEXT_BLOCK);\n" +
+ " }\n" +
+ "}\n"
+ },
+ "public class A {\n" +
+ " public void foo() { \n" +
+ " String k = \"\"\"\n" +
+ " abcdefg\n" +
+ " \"\"\"\n" +
+ " System.out.println(\"abc\"); \n" +
+ " }\n" +
+ "}",
+ getCompilerOptions(),
+ new String[] {"--enable-preview"});
+ }
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
index 1d7d3eb..18ce0d9 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,8 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Alexander Kriegisch - bug 286316: Set classpath for forked test JVM via
+ * DataOutputStream instead of JVM parameter; improve file deletion logic
*******************************************************************************/
package org.eclipse.jdt.core.tests.util;
@@ -17,6 +19,10 @@
import org.eclipse.jdt.core.tests.runtime.*;
import java.io.*;
import java.net.*;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
/**
* Verifies that the .class files resulting from a compilation can be loaded
* in a VM and that they can be run.
@@ -128,222 +134,95 @@
public String getExecutionError(){
return this.errorBuffer.toString();
}
+
/**
- * Returns the code of the VerifyTests class.
- *
+ * Default value for {@link VerifyTests} source code, copied and regularly refreshed from original source code
+ * <p>
* IMPORTANT NOTE: DO NOTE EDIT BUT GENERATE INSTEAD (see below)
- *
- * To generate:
- * - export VerifyTests.java to d:/temp
- * - inspect org.eclipse.jdt.core.tests.util.Util.fileContentToDisplayString("d:/temp/VerifyTests.java", 2, true)
+ * <p>
+ * To generate:<ul>
+ * <li>export VerifyTests.java to d:/temp</li>
+ * <li>inspect org.eclipse.jdt.core.tests.util.Util.fileContentToDisplayString("d:/temp/VerifyTests.java", 2, true)</li>
+ * </ul><p>
*/
-private String getVerifyTestsCode() {
- return
+static final String VERIFY_TEST_CODE_DEFAULT;
+
+static {
+ // Use static initialiser block instead of direct field initialisation, because it permits for code folding in IDEs,
+ // i.e. this huge string can easily be folded away, which minimises scrolling.
+ VERIFY_TEST_CODE_DEFAULT =
"/*******************************************************************************\n" +
- " * Copyright (c) 2000, 2017 IBM Corporation and others.\n" +
- " * All rights reserved. This program and the accompanying materials\n" +
- " * are made available under the terms of the Eclipse Public License v1.0\n" +
+ " * Copyright (c) 2000, 2021 IBM Corporation and others.\n" +
+ " *\n" +
+ " * This program and the accompanying materials\n" +
+ " * are made available under the terms of the Eclipse Public License 2.0\n" +
" * which accompanies this distribution, and is available at\n" +
- " * http://www.eclipse.org/legal/epl-v10.html\n" +
+ " * https://www.eclipse.org/legal/epl-2.0/\n" +
+ " *\n" +
+ " * SPDX-License-Identifier: EPL-2.0\n" +
" *\n" +
" * Contributors:\n" +
" * IBM Corporation - initial API and implementation\n" +
+ " * Alexander Kriegisch - bug 286316: Get classpath via DataInputStream and\n" +
+ " * use it in an isolated URLClassLoader, enabling formerly locked\n" +
+ " * classpath JARs to be closed on Windows\n" +
" *******************************************************************************/\n" +
"package org.eclipse.jdt.core.tests.util;\n" +
"\n" +
"import java.io.DataInputStream;\n" +
"import java.io.DataOutputStream;\n" +
"import java.io.File;\n" +
- "import java.io.FileInputStream;\n" +
- "import java.io.FileNotFoundException;\n" +
"import java.io.IOException;\n" +
- "import java.io.InputStream;\n" +
"import java.lang.reflect.InvocationTargetException;\n" +
"import java.lang.reflect.Method;\n" +
+ "import java.net.MalformedURLException;\n" +
"import java.net.Socket;\n" +
- "import java.util.StringTokenizer;\n" +
+ "import java.net.URL;\n" +
+ "import java.net.URLClassLoader;\n" +
"\n" +
- "/******************************************************\n" +
- " *\n" +
- " * IMPORTANT NOTE: If modifying this class, copy the source to TestVerifier#getVerifyTestsCode()\n" +
- " * (see this method for details)\n" +
- " *\n" +
- " ******************************************************/\n" +
- "\n" +
+ "/**\n" +
+ " * <b>IMPORTANT NOTE:</b> When modifying this class, please copy the source into the static initialiser block for field\n" +
+ " * {@link TestVerifier#VERIFY_TEST_CODE_DEFAULT}. See also {@link TestVerifier#READ_VERIFY_TEST_FROM_FILE}, if you want\n" +
+ " * to dynamically load the source code directly from this file when running tests, which is a convenient way to test if\n" +
+ " * changes in this class work as expected, without the need to update the hard-coded default value every single time\n" +
+ " * during an ongoing refactoring.\n" +
+ " * <p>\n" +
+ " * In order to make the copying job easier, keep this class compatible with Java 5 language level. You may however use\n" +
+ " * things like {@code @Override} for interfaces, {@code assert} (if in a single line), {@code @SuppressWarnings},\n" +
+ " * because {@link TestVerifier#getVerifyTestsCode()} can filter them out dynamically. You should however avoid things\n" +
+ " * like diamonds, multi-catch, catch-with-resources and more recent Java features.\n" +
+ " */\n" +
+ "@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n" +
"public class VerifyTests {\n" +
" int portNumber;\n" +
" Socket socket;\n" +
"\n" +
- "/**\n" +
- " * NOTE: Code copied from junit.util.TestCaseClassLoader.\n" +
- " *\n" +
- " * A custom class loader which enables the reloading\n" +
- " * of classes for each test run. The class loader\n" +
- " * can be configured with a list of package paths that\n" +
- " * should be excluded from loading. The loading\n" +
- " * of these packages is delegated to the system class\n" +
- " * loader. They will be shared across test runs.\n" +
- " * <p>\n" +
- " * The list of excluded package paths is specified in\n" +
- " * a properties file \"excluded.properties\" that is located in\n" +
- " * the same place as the TestCaseClassLoader class.\n" +
- " * <p>\n" +
- " * <b>Known limitation:</b> the VerifyClassLoader cannot load classes\n" +
- " * from jar files.\n" +
- " */\n" +
- "\n" +
- "\n" +
- "public class VerifyClassLoader extends ClassLoader {\n" +
- " /** scanned class path */\n" +
- " private String[] pathItems;\n" +
- "\n" +
- " /** excluded paths */\n" +
- " private String[] excluded= {};\n" +
- "\n" +
- " /**\n" +
- " * Constructs a VerifyClassLoader. It scans the class path\n" +
- " * and the excluded package paths\n" +
- " */\n" +
- " public VerifyClassLoader() {\n" +
- " super();\n" +
- " String classPath= System.getProperty(\"java.class.path\");\n" +
- " String separator= System.getProperty(\"path.separator\");\n" +
- "\n" +
- " // first pass: count elements\n" +
- " StringTokenizer st= new StringTokenizer(classPath, separator);\n" +
- " int i= 0;\n" +
- " while (st.hasMoreTokens()) {\n" +
- " st.nextToken();\n" +
- " i++;\n" +
- " }\n" +
- " // second pass: split\n" +
- " this.pathItems= new String[i];\n" +
- " st= new StringTokenizer(classPath, separator);\n" +
- " i= 0;\n" +
- " while (st.hasMoreTokens()) {\n" +
- " this.pathItems[i++]= st.nextToken();\n" +
- " }\n" +
- "\n" +
+ "private static URL[] classPathToURLs(String[] classPath) throws MalformedURLException {\n" +
+ " URL[] urls = new URL[classPath.length];\n" +
+ " for (int i = 0; i < classPath.length; i++) {\n" +
+ " urls[i] = new File(classPath[i]).toURI().toURL();\n" +
" }\n" +
- " public java.net.URL getResource(String name) {\n" +
- " return ClassLoader.getSystemResource(name);\n" +
- " }\n" +
- " public InputStream getResourceAsStream(String name) {\n" +
- " return ClassLoader.getSystemResourceAsStream(name);\n" +
- " }\n" +
- " protected boolean isExcluded(String name) {\n" +
- " // exclude the \"java\" packages.\n" +
- " // They always need to be excluded so that they are loaded by the system class loader\n" +
- " if (name.startsWith(\"java\") || name.startsWith(\"[Ljava\"))\n" +
- " return true;\n" +
- "\n" +
-//{ObjectTeams: don't process core OT-classes either (unpacked .class not available on classpath):
- " if (name.startsWith(\"org.objectteams\"))\n" +
- " return true;\n" +
- " \n" +
- " if (name.startsWith(\"org.eclipse.objectteams.otre\"))\n" +
- " return true;\n" +
- " \n" +
- " if (name.startsWith(\"org.apache.bcel\"))\n" +
- " return true;\n" +
- " \n" +
- " if (name.startsWith(\"sun\"))\n" + // have a test that needs sun/reflect/SerializationConstructorAccessorImpl
- " return true;\n" +
- " \n" +
-// SH}
- " // exclude the user defined package paths\n" +
- " for (int i= 0; i < this.excluded.length; i++) {\n" +
- " if (name.startsWith(this.excluded[i])) {\n" +
- " return true;\n" +
- " }\n" +
- " }\n" +
- " return false;\n" +
- " }\n" +
- " public synchronized Class loadClass(String name, boolean resolve)\n" +
- " throws ClassNotFoundException {\n" +
- "\n" +
- " Class c= findLoadedClass(name);\n" +
- " if (c != null)\n" +
- " return c;\n" +
- " //\n" +
- " // Delegate the loading of excluded classes to the\n" +
- " // standard class loader.\n" +
- " //\n" +
- " if (isExcluded(name)) {\n" +
- " try {\n" +
- " c= findSystemClass(name);\n" +
- " return c;\n" +
- " } catch (ClassNotFoundException e) {\n" +
- " // keep searching\n" +
- " }\n" +
- " }\n" +
- " File file= locate(name);\n" +
- " if (file == null)\n" +
- " throw new ClassNotFoundException();\n" +
- " byte data[]= loadClassData(file);\n" +
- " c= defineClass(name, data, 0, data.length);\n" +
- " if (resolve)\n" +
- " resolveClass(c);\n" +
- " return c;\n" +
- " }\n" +
- " private byte[] loadClassData(File f) throws ClassNotFoundException {\n" +
- " FileInputStream stream = null;\n" +
- " try {\n" +
- " //System.out.println(\"loading: \"+f.getPath());\n" +
- " stream = new FileInputStream(f);\n" +
- "\n" +
- " try {\n" +
- " byte[] b= new byte[stream.available()];\n" +
- " stream.read(b);\n" +
- " return b;\n" +
- " }\n" +
- " catch (IOException e) {\n" +
- " throw new ClassNotFoundException();\n" +
- " }\n" +
- " }\n" +
- " catch (FileNotFoundException e) {\n" +
- " throw new ClassNotFoundException();\n" +
- " } finally {\n" +
- " if (stream != null) {\n" +
- " try {\n" +
- " stream.close();\n" +
- " } catch (IOException e) {\n" +
- " /* ignore */\n" +
- " }\n" +
- " }\n" +
- " }\n" +
- " }\n" +
- " /**\n" +
- " * Locate the given file.\n" +
- " * @return Returns null if file couldn't be found.\n" +
- " */\n" +
- " private File locate(String fileName) {\n" +
- " if (fileName != null) {\n" +
- " fileName= fileName.replace('.', '/')+\".class\";\n" +
- " File path= null;\n" +
- " for (int i= 0; i < this.pathItems.length; i++) {\n" +
- " path= new File(this.pathItems[i], fileName);\n" +
- " if (path.exists())\n" +
- " return path;\n" +
- " }\n" +
- " }\n" +
- " return null;\n" +
- " }\n" +
+ " return urls;\n" +
"}\n" +
"\n" +
- "public void loadAndRun(String className) throws Throwable {\n" +
- " //System.out.println(\"Loading \" + className + \"...\");\n" +
- " Class testClass = new VerifyClassLoader().loadClass(className);\n" +
- " //System.out.println(\"Loaded \" + className);\n" +
+ "public void loadAndRun(String className, String[] classPath) throws Throwable {\n" +
+ " URLClassLoader urlClassLoader = new URLClassLoader(classPathToURLs(classPath));\n" +
" try {\n" +
- " Method main = testClass.getMethod(\"main\", new Class[] {String[].class});\n" +
- " //System.out.println(\"Running \" + className);\n" +
- " main.invoke(null, new Object[] {new String[] {}});\n" +
- " //System.out.println(\"Finished running \" + className);\n" +
- " } catch (NoSuchMethodException e) {\n" +
- " return;\n" +
- " } catch (InvocationTargetException e) {\n" +
- " throw e.getTargetException();\n" +
+ " //System.out.println(\"Loading \" + className + \"...\");\n" +
+ " Class testClass = urlClassLoader.loadClass(className);\n" +
+ " //System.out.println(\"Loaded \" + className);\n" +
+ " try {\n" +
+ " Method main = testClass.getMethod(\"main\", new Class[] {String[].class});\n" +
+ " //System.out.println(\"Running \" + className);\n" +
+ " main.invoke(null, new Object[] {new String[] {}});\n" +
+ " //System.out.println(\"Finished running \" + className);\n" +
+ " } catch (NoSuchMethodException e) {\n" +
+ " return;\n" +
+ " } catch (InvocationTargetException e) {\n" +
+ " throw e.getTargetException();\n" +
+ " }\n" +
+ " } finally {\n" +
+ " urlClassLoader.close();\n" +
" }\n" +
"}\n" +
"public static void main(String[] args) throws IOException {\n" +
@@ -359,35 +238,147 @@
" final DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());\n" +
" while (true) {\n" +
" final String className = in.readUTF();\n" +
+ " final int length = in.readInt();\n" +
+ " final String[] classPath = new String[length];\n" +
+ " for (int i = 0; i < length; i++) {\n" +
+ " classPath[i] = in.readUTF();\n" +
+ " }\n" +
" Thread thread = new Thread() {\n" +
+ " @Override\n" +
" public void run() {\n" +
" try {\n" +
- " loadAndRun(className);\n" +
+ " loadAndRun(className, classPath);\n" +
" out.writeBoolean(true);\n" +
- " System.err.println(VerifyTests.class.getName());\n" +
" System.out.println(VerifyTests.class.getName());\n" +
+ " System.err.println(VerifyTests.class.getName());\n" +
" } catch (Throwable e) {\n" +
" e.printStackTrace();\n" +
" try {\n" +
- " System.err.println(VerifyTests.class.getName());\n" +
- " System.out.println(VerifyTests.class.getName());\n" +
" out.writeBoolean(false);\n" +
+ " System.out.println(VerifyTests.class.getName());\n" +
+ " System.err.println(VerifyTests.class.getName());\n" +
" } catch (IOException e1) {\n" +
" e1.printStackTrace();\n" +
" }\n" +
" }\n" +
+ " // Flush all streams, in case the test executor VM is shut down before\n" +
+ " // the controlling VM receives the responses it depends on\n" +
" try {\n" +
" out.flush();\n" +
" } catch (IOException e) {\n" +
" e.printStackTrace();\n" +
" }\n" +
+ " System.out.flush();\n" +
+ " System.err.flush();\n" +
" }\n" +
" };\n" +
" thread.start();\n" +
" }\n" +
"}\n" +
- "}";
+ "}\n";
}
+
+/**
+ * Activate, if you want to read the {@link VerifyTests} source code directly from the file system in
+ * {@link #getVerifyTestsCode()}, e.g. during development while refactoring the source code.
+ */
+public static boolean READ_VERIFY_TEST_FROM_FILE = false;
+/**
+ * Adjust, if in {@link #READ_VERIFY_TEST_FROM_FILE} mode method {@link #getVerifyTestsCode()} cannot find
+ * the source file based on the current directory. In that case, set the correct JDT Core project base
+ * directory as PROJECT_BASE_DIR environment variable, so that the 'org.eclipse.jdt.core.tests.compiler/src'
+ * sub-directory can be found from there.
+ */
+public static String PROJECT_BASE_DIR = System.getenv("PROJECT_BASE_DIR");
+
+// Cached value for VerifyTests.java source code, read only once, either directly from the source code directory or
+// from VERIFY_TEST_CODE_DEFAULT
+private static String verifyTestCode;
+
+// Helper object for guarding 'verifyTestCode' with 'synchronized (verifyTestCodeLock)', in case tests are to be run in
+// parallel
+private static final Object verifyTestCodeLock = new Object();
+
+/**
+ * Returns {@link VerifyTests} source code, to be used as a boot-strapping class in forked test JVMs
+ * <p>
+ * Optionally, you can use {@link #READ_VERIFY_TEST_FROM_FILE} in order to read the source code from the project's
+ * source directory. If it is not found automatically, you may also adjust {@link #PROJECT_BASE_DIR}. Both values are
+ * public and writable during runtime.
+ * <p>
+ * <b>Caveat:</b> The return value is only lazily initialised once, then cached. If you change
+ * {@link #READ_VERIFY_TEST_FROM_FILE} after calling this method for the first time, the return value will not change
+ * anymore.
+ *
+ * @return {@link VerifyTests} source code, filtered by {@link #filterSourceCode(Stream)}
+ */
+String getVerifyTestsCode() {
+ synchronized (verifyTestCodeLock) {
+ if (verifyTestCode == null) {
+ if (READ_VERIFY_TEST_FROM_FILE) {
+ String sourceFile = "src/org/eclipse/jdt/core/tests/util/VerifyTests.java";
+ if (!new File(sourceFile).exists()) {
+ sourceFile = PROJECT_BASE_DIR + "/org.eclipse.jdt.core.tests.compiler/" + sourceFile;
+ }
+ try (BufferedReader reader = new BufferedReader(new FileReader(sourceFile))) {
+ verifyTestCode = filterSourceCode(reader.lines());
+ }
+ catch (IOException e) {
+ System.out.println("WARNING: Cannot read & filter VerifyTests source code from file, using default value");
+ System.out.println(" - exception: " + e);
+ }
+ }
+ }
+ if (verifyTestCode == null) {
+ try (BufferedReader reader = new BufferedReader(new StringReader(VERIFY_TEST_CODE_DEFAULT))) {
+ verifyTestCode = filterSourceCode(reader.lines());
+ }
+ catch (IOException e) {
+ System.out.println("WARNING: Cannot filter VerifyTests source code default value, using unfiltered value");
+ System.out.println(" - exception: " + e);
+ verifyTestCode = VERIFY_TEST_CODE_DEFAULT;
+ }
+ }
+ return verifyTestCode;
+ }
+}
+
+/**
+ * Filter some elements incompatible with Java source level 1.5 from source code
+ * <p>
+ * This method cannot convert things like catch-with-resources or other language elements back to Java 1.5, you have to
+ * take care of keeping the source code backward compatible by yourself. But a few things you can still use in the
+ * source code, such as {@code @SuppressWarnings}, {@code @Override} in interfaces or single-line {@code assert}.
+ *
+ * @param sourceCodeLines stream of source code lines
+ * @return filtered source code file as a string
+ */
+private String filterSourceCode(Stream<String> sourceCodeLines) {
+ return sourceCodeLines
+ .filter(s -> !(s.contains("@SuppressWarnings") || s.contains("@Override") || s.contains("assert ")))
+ .collect(Collectors.joining("\n"));
+}
+
+/**
+ * Remove non-essential parts of the test JVM classpath
+ * <p>
+ * The classpath for the forked test JVM should only contain JDK paths and the 'verifier' subdirectory where the
+ * {@link VerifyTests} class boot-strapping the test resides, because those need to be present during JVM start-up.
+ * Other parts of the classpath are stripped off, because they are to be communicated to the forked JVM via direct
+ * socket communication.
+ *
+ * @param classPath full classpath
+ * @return minimal classpath necessary for forked test JVM boot-strapping
+ */
+private String[] getMinimalClassPath(String[] classPath) {
+return Arrays.stream(classPath)
+ .filter(s -> {
+ String path = s.replace('\\', '/');
+ return !path.contains("/comptest/") || path.endsWith("/verifier");
+ })
+ .toArray(String[]::new);
+}
+
private void launchAndRun(String className, String[] classpaths, String[] programArguments, String[] vmArguments) {
// we won't reuse the vm, shut the existing one if running
if (this.vm != null) {
@@ -492,7 +483,7 @@
String verifierDir = Util.getOutputDirectory() + File.separator + "verifier";
compileVerifyTests(verifierDir);
cp[length] = verifierDir;
- launcher.setClassPath(cp);
+ launcher.setClassPath(getMinimalClassPath(cp));
launcher.setVMPath(Util.getJREDirectory());
if (vmArguments != null) {
String[] completeVmArguments = new String[vmArguments.length + 1];
@@ -582,11 +573,17 @@
* Loads and runs the given class.
* Return whether no exception was thrown while running the class.
*/
-private boolean loadAndRun(String className) {
+private boolean loadAndRun(String className, String[] classPath) {
if (this.socket != null) {
try {
DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());
out.writeUTF(className);
+ if (classPath == null)
+ classPath = new String[0];
+ out.writeInt(classPath.length);
+ for (String classpath : classPath) {
+ out.writeUTF(classpath);
+ }
DataInputStream in = new DataInputStream(this.socket.getInputStream());
try {
boolean result = in.readBoolean();
@@ -649,7 +646,7 @@
this.errorBuffer = new StringBuffer();
if (this.reuseVM && programArguments == null) {
launchVerifyTestsIfNeeded(classpaths, vmArguments);
- loadAndRun(className);
+ loadAndRun(className, classpaths);
} else {
launchAndRun(className, classpaths, programArguments, vmArguments);
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java
index 67a3d17..6ec6faa 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,192 +10,66 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Alexander Kriegisch - bug 286316: Get classpath via DataInputStream and
+ * use it in an isolated URLClassLoader, enabling formerly locked
+ * classpath JARs to be closed on Windows
*******************************************************************************/
package org.eclipse.jdt.core.tests.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.net.MalformedURLException;
import java.net.Socket;
-import java.util.StringTokenizer;
+import java.net.URL;
+import java.net.URLClassLoader;
-/******************************************************
- *
- * IMPORTANT NOTE: If modifying this class, copy the source to TestVerifier#getVerifyTestsCode()
- * (see this method for details)
- *
- ******************************************************/
-
+/**
+ * <b>IMPORTANT NOTE:</b> When modifying this class, please copy the source into the static initialiser block for field
+ * {@link TestVerifier#VERIFY_TEST_CODE_DEFAULT}. See also {@link TestVerifier#READ_VERIFY_TEST_FROM_FILE}, if you want
+ * to dynamically load the source code directly from this file when running tests, which is a convenient way to test if
+ * changes in this class work as expected, without the need to update the hard-coded default value every single time
+ * during an ongoing refactoring.
+ * <p>
+ * In order to make the copying job easier, keep this class compatible with Java 5 language level. You may however use
+ * things like {@code @Override} for interfaces, {@code assert} (if in a single line), {@code @SuppressWarnings},
+ * because {@link TestVerifier#getVerifyTestsCode()} can filter them out dynamically. You should however avoid things
+ * like diamonds, multi-catch, catch-with-resources and more recent Java features.
+ */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class VerifyTests {
int portNumber;
Socket socket;
-/**
- * NOTE: Code copied from junit.util.TestCaseClassLoader.
- *
- * A custom class loader which enables the reloading
- * of classes for each test run. The class loader
- * can be configured with a list of package paths that
- * should be excluded from loading. The loading
- * of these packages is delegated to the system class
- * loader. They will be shared across test runs.
- * <p>
- * The list of excluded package paths is specified in
- * a properties file "excluded.properties" that is located in
- * the same place as the TestCaseClassLoader class.
- * <p>
- * <b>Known limitation:</b> the VerifyClassLoader cannot load classes
- * from jar files.
- */
-
-
-public class VerifyClassLoader extends ClassLoader {
- /** scanned class path */
- private String[] pathItems;
-
- /** excluded paths */
- private String[] excluded= {};
-
- /**
- * Constructs a VerifyClassLoader. It scans the class path
- * and the excluded package paths
- */
- public VerifyClassLoader() {
- super();
- String classPath= System.getProperty("java.class.path");
- String separator= System.getProperty("path.separator");
-
- // first pass: count elements
- StringTokenizer st= new StringTokenizer(classPath, separator);
- int i= 0;
- while (st.hasMoreTokens()) {
- st.nextToken();
- i++;
- }
- // second pass: split
- this.pathItems= new String[i];
- st= new StringTokenizer(classPath, separator);
- i= 0;
- while (st.hasMoreTokens()) {
- this.pathItems[i++]= st.nextToken();
- }
-
+private static URL[] classPathToURLs(String[] classPath) throws MalformedURLException {
+ URL[] urls = new URL[classPath.length];
+ for (int i = 0; i < classPath.length; i++) {
+ urls[i] = new File(classPath[i]).toURI().toURL();
}
- @Override
- public java.net.URL getResource(String name) {
- return ClassLoader.getSystemResource(name);
- }
- @Override
- public InputStream getResourceAsStream(String name) {
- return ClassLoader.getSystemResourceAsStream(name);
- }
- protected boolean isExcluded(String name) {
- // exclude the "java" packages.
- // They always need to be excluded so that they are loaded by the system class loader
- if (name.startsWith("java") || name.startsWith("[Ljava"))
- return true;
-
- // exclude the user defined package paths
- for (int i= 0; i < this.excluded.length; i++) {
- if (name.startsWith(this.excluded[i])) {
- return true;
- }
- }
- return false;
- }
- @Override
- public synchronized Class loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
-
- Class c= findLoadedClass(name);
- if (c != null)
- return c;
- //
- // Delegate the loading of excluded classes to the
- // standard class loader.
- //
- if (isExcluded(name)) {
- try {
- c= findSystemClass(name);
- return c;
- } catch (ClassNotFoundException e) {
- // keep searching
- }
- }
- File file= locate(name);
- if (file == null)
- throw new ClassNotFoundException();
- byte data[]= loadClassData(file);
- c= defineClass(name, data, 0, data.length);
- if (resolve)
- resolveClass(c);
- return c;
- }
- private byte[] loadClassData(File f) throws ClassNotFoundException {
- FileInputStream stream = null;
- try {
- //System.out.println("loading: "+f.getPath());
- stream = new FileInputStream(f);
-
- try {
- byte[] b= new byte[stream.available()];
- stream.read(b);
- return b;
- }
- catch (IOException e) {
- throw new ClassNotFoundException();
- }
- }
- catch (FileNotFoundException e) {
- throw new ClassNotFoundException();
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- /* ignore */
- }
- }
- }
- }
- /**
- * Locate the given file.
- * @return Returns null if file couldn't be found.
- */
- private File locate(String fileName) {
- if (fileName != null) {
- fileName= fileName.replace('.', '/')+".class";
- File path= null;
- for (int i= 0; i < this.pathItems.length; i++) {
- path= new File(this.pathItems[i], fileName);
- if (path.exists())
- return path;
- }
- }
- return null;
- }
+ return urls;
}
-public void loadAndRun(String className) throws Throwable {
- //System.out.println("Loading " + className + "...");
- Class testClass = new VerifyClassLoader().loadClass(className);
- //System.out.println("Loaded " + className);
+public void loadAndRun(String className, String[] classPath) throws Throwable {
+ URLClassLoader urlClassLoader = new URLClassLoader(classPathToURLs(classPath));
try {
- Method main = testClass.getMethod("main", new Class[] {String[].class});
- //System.out.println("Running " + className);
- main.invoke(null, new Object[] {new String[] {}});
- //System.out.println("Finished running " + className);
- } catch (NoSuchMethodException e) {
- return;
- } catch (InvocationTargetException e) {
- throw e.getTargetException();
+ //System.out.println("Loading " + className + "...");
+ Class testClass = urlClassLoader.loadClass(className);
+ //System.out.println("Loaded " + className);
+ try {
+ Method main = testClass.getMethod("main", new Class[] {String[].class});
+ //System.out.println("Running " + className);
+ main.invoke(null, new Object[] {new String[] {}});
+ //System.out.println("Finished running " + className);
+ } catch (NoSuchMethodException e) {
+ return;
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ } finally {
+ urlClassLoader.close();
}
}
public static void main(String[] args) throws IOException {
@@ -211,11 +85,16 @@
final DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());
while (true) {
final String className = in.readUTF();
+ final int length = in.readInt();
+ final String[] classPath = new String[length];
+ for (int i = 0; i < length; i++) {
+ classPath[i] = in.readUTF();
+ }
Thread thread = new Thread() {
@Override
public void run() {
try {
- loadAndRun(className);
+ loadAndRun(className, classPath);
out.writeBoolean(true);
System.out.println(VerifyTests.class.getName());
System.err.println(VerifyTests.class.getName());
diff --git a/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8src.zip b/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8src.zip
index 1aa9c7b..8b7670a 100644
--- a/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8src.zip
+++ b/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8src.zip
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
index 076d523..40b9217 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
@@ -876,6 +876,17 @@
);
}
+ protected void assertResourceOnClasspathEntry(IJavaProject project, IResource resource, String path) {
+ IClasspathEntry cp = project.findContainingClasspathEntry(resource);
+ assertNotNull("IClasspathEntry exists for the resource", cp);
+ assertEquals("In the expected classpath entry", path, cp.getPath().toPortableString());
+ }
+
+ protected void assertResourceNotOnClasspathEntry(IJavaProject project, IResource resource) {
+ IClasspathEntry cp = project.findContainingClasspathEntry(resource);
+ assertNull("IClasspathEntry does not exists for the resource", cp);
+ }
+
protected void assertResourceTreeEquals(String message, String expected, Object[] resources) throws CoreException {
sortResources(resources);
StringBuffer buffer = new StringBuffer();
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
index 8590fb3..1d51456 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
@@ -18,6 +18,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import org.eclipse.jdt.core.tests.compiler.CharDeduplicationTest;
import org.eclipse.jdt.core.tests.compiler.map.CharArrayMapperTest;
import org.eclipse.jdt.core.tests.junit.extension.TestCase;
@@ -229,6 +230,8 @@
JavaModelManagerTests.class,
CharArrayMapperTest.class,
+
+ CharDeduplicationTest.class,
};
Class[] deprecatedClasses = getDeprecatedJDOMTestClasses();
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionContextTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionContextTests.java
index 18fda7a..0a9a3e9 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionContextTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionContextTests.java
@@ -2489,8 +2489,8 @@
"completion range=["+(tokenStart)+", "+(tokenEnd)+"]\n" +
"completion token=\"\"\n" +
"completion token kind=TOKEN_KIND_NAME\n" +
- "expectedTypesSignatures=null\n" +
- "expectedTypesKeys=null\n"+
+ "expectedTypesSignatures={I}\n" +
+ "expectedTypesKeys={I}\n"+
"completion token location=UNKNOWN",
result.context);
}
@@ -2545,8 +2545,8 @@
"completion range=["+(tokenStart)+", "+(tokenEnd)+"]\n" +
"completion token=\"\"\n" +
"completion token kind=TOKEN_KIND_NAME\n" +
- "expectedTypesSignatures=null\n" +
- "expectedTypesKeys=null\n"+
+ "expectedTypesSignatures={I}\n" +
+ "expectedTypesKeys={I}\n"+
"completion token location=UNKNOWN",
result.context);
}
@@ -2601,8 +2601,8 @@
"completion range=["+(tokenStart)+", "+(tokenEnd)+"]\n" +
"completion token=\"\"\n" +
"completion token kind=TOKEN_KIND_NAME\n" +
- "expectedTypesSignatures=null\n" +
- "expectedTypesKeys=null\n"+
+ "expectedTypesSignatures={I}\n" +
+ "expectedTypesKeys={I}\n"+
"completion token location=UNKNOWN",
result.context);
}
@@ -2657,8 +2657,8 @@
"completion range=["+(tokenStart)+", "+(tokenEnd)+"]\n" +
"completion token=\"\"\n" +
"completion token kind=TOKEN_KIND_NAME\n" +
- "expectedTypesSignatures=null\n" +
- "expectedTypesKeys=null\n"+
+ "expectedTypesSignatures={I}\n" +
+ "expectedTypesKeys={I}\n"+
"completion token location=UNKNOWN",
result.context);
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java
index cd84004..b0e1172 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java
@@ -13324,6 +13324,7 @@
int tEnd = tStart;
assertResults(
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, replace["+tStart+", "+tEnd+"], token["+tStart+", "+tEnd+"], 52}\n" +
"xBar[METHOD_REF]{CompletionPrefixMethodName3.this.xBar(1,, LCompletionPrefixMethodName3;, (II)I, xBar, (a, b), replace["+rStart1+", "+rEnd1+"], token["+tStart+", "+tEnd+"], "+(R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME+ R_NON_RESTRICTED)+"}\n"+
"xBar[METHOD_REF]{, LCompletionPrefixMethodName3$classFoo;, (II)I, xBar, (a, b), replace["+rStart2+", "+rEnd2+"], token["+tStart+", "+tEnd+"], "+(R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME + R_UNQUALIFIED + R_NON_RESTRICTED)+"}",
requestor.getResults());
@@ -19294,9 +19295,7 @@
"StaticMembers.StaticClazz[TYPE_REF]{StaticClazz, test, Ltest.StaticMembers$StaticClazz;, null, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_INHERITED + R_NON_RESTRICTED) + "}\n" +
"class[FIELD_REF]{class, null, Ljava.lang.Class;, class, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_INHERITED + R_NON_RESTRICTED) + "}\n" +
"staticField[FIELD_REF]{staticField, Ltest.StaticMembers;, I, staticField, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_INHERITED + R_NON_RESTRICTED) + "}\n" +
- "staticMethod[METHOD_REF]{staticMethod(), Ltest.StaticMembers;, ()I, staticMethod, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_INHERITED + R_NON_RESTRICTED) + "}\n" +
- "super[KEYWORD]{super, null, null, super, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_INHERITED + R_NON_RESTRICTED) + "}\n" +
- "this[KEYWORD]{this, null, null, this, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_INHERITED + R_NON_RESTRICTED) + "}",
+ "staticMethod[METHOD_REF]{staticMethod(), Ltest.StaticMembers;, ()I, staticMethod, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_INHERITED + R_NON_RESTRICTED) + "}",
requestor.getResults());
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=99631
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
index 90aad65..a3c593d 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
@@ -26,6 +26,7 @@
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.eval.IEvaluationContext;
import org.eclipse.jdt.internal.codeassist.RelevanceConstants;
@@ -242,7 +243,8 @@
int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
assertResults(
- "argument[LOCAL_VARIABLE_REF]{argument, null, Ljava.lang.Object;, argument, null, " + (R_DEFAULT + 21) + "}", // FIXME should be "I" and 22 like test006
+ "argument[LOCAL_VARIABLE_REF]{argument, null, Ljava.lang.Object;, argument, null, 51}\n" // FIXME should be "I" and 22 like test006
+ + "[LAMBDA_EXPRESSION]{->, LI;, (I)I, foo, (x), 89}",
requestor.getResults());
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=405126, [1.8][code assist] Lambda parameters incorrectly recovered as fields.
@@ -5948,8 +5950,8 @@
int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
String result = requestor.getResults();
- assertResults("getMinimum[METHOD_REF]{, Ljava.util.Calendar;, (I)I, getMinimum, (arg0), 86}",
- result);
+ assertResults("num[FIELD_REF]{num, LLambdaFreeze2;, I, num, null, 52}\n"
+ + "getMinimum[METHOD_REF]{, Ljava.util.Calendar;, (I)I, getMinimum, (arg0), 86}", result);
}
public void testBug574912_comment6b() throws JavaModelException {
this.workingCopies = new ICompilationUnit[1];
@@ -6024,4 +6026,163 @@
"completion token location={STATEMENT_START}", // this is required for sysout template proposal
requestor.getContext());
}
+public void testBug575149_expectOverloadedMethodsAndVariablesRankedWithExpectedType() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Bug443091.java",
+ "import java.util.function.Consumer;\n" +
+ "import java.util.function.Function;\n" +
+ "\n" +
+ "public class Bug443091 {\n" +
+ " private void foo() {\n" +
+ " Consumer<Integer> capture = null;\n" +
+ " forEach()" +
+ " }\n" +
+ " private void forEach(Consumer<Integer> in) {}\n" +
+ " private void forEach(Function<Integer, String> in) {}\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "forEach(";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ String result = requestor.getResults();
+ assertResults(
+ "capture[LOCAL_VARIABLE_REF]{capture, null, Ljava.util.function.Consumer<Ljava.lang.Integer;>;, capture, null, 52}\n"
+ + "forEach[METHOD_REF]{, LBug443091;, (Ljava.util.function.Consumer<Ljava.lang.Integer;>;)V, forEach, (in), 56}\n"
+ + "forEach[METHOD_REF]{, LBug443091;, (Ljava.util.function.Function<Ljava.lang.Integer;Ljava.lang.String;>;)V, forEach, (in), 56}\n"
+ + "[LAMBDA_EXPRESSION]{->, Ljava.util.function.Function<Ljava.lang.Integer;Ljava.lang.String;>;, (Ljava.lang.Integer;)Ljava.lang.String;, apply, (arg0), 89}\n"
+ + "[LAMBDA_EXPRESSION]{->, Ljava.util.function.Consumer<Ljava.lang.Integer;>;, (Ljava.lang.Integer;)V, accept, (t), 89}",
+ result);
+ assertTrue("expected type signatures don't match", CharOperation.equals(requestor.getExpectedTypesSignatures(),
+ new char[][] {"Ljava.util.function.Function<Ljava.lang.Integer;Ljava.lang.String;>;".toCharArray(),
+ "Ljava.util.function.Consumer<Ljava.lang.Integer;>;".toCharArray()}, true));
+}
+public void testBug575149_expectRemainingOverloadedMethodsMatchingFilledArguments() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Bug443091.java",
+ "import java.util.function.Consumer;\n" +
+ "import java.util.function.Function;\n" +
+ "\n" +
+ "public class Bug443091 {\n" +
+ " private void foo() {\n" +
+ " Consumer<Integer> capture = null;\n" +
+ " forEach(capture, )" +
+ " }\n" +
+ " private void forEach(Consumer<Integer> in) {}\n" +
+ " private void forEach(Consumer<Integer> in, Integer limit) {}\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "forEach(capture,";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ String result = requestor.getResults();
+ assertResults("hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 52}\n"
+ + "forEach[METHOD_REF]{, LBug443091;, (Ljava.util.function.Consumer<Ljava.lang.Integer;>;)V, forEach, (in), 56}\n"
+ + "forEach[METHOD_REF]{, LBug443091;, (Ljava.util.function.Consumer<Ljava.lang.Integer;>;Ljava.lang.Integer;)V, forEach, (in, limit), 56}",
+ result);
+ assertTrue("expected type signatures don't match", CharOperation.equals(requestor.getExpectedTypesSignatures(), new char[][] {"Ljava.lang.Integer;".toCharArray()}, true));
+}
+public void testBug575149_expectOverloadsOverEnumLiterals() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Bug443091.java",
+ "import java.util.function.Consumer;\n" +
+ "import java.util.function.Function;\n" +
+ "\n" +
+ "public class Bug443091 {\n" +
+ " private void foo() {\n" +
+ " Consumer<Integer> capture = null;\n" +
+ " forEach(capture, )" +
+ " }\n" +
+ " private Thread.State defaultState() { return null;} \n" +
+ " private void forEach(Consumer<Integer> in, Thread.State state) {}\n" +
+ " private void forEach(Consumer<Integer> in, Thread.State state, Integer limit) {}\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "forEach(capture,";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ String result = requestor.getResults();
+ assertResults("BLOCKED[FIELD_REF]{State.BLOCKED, Ljava.lang.Thread$State;, Ljava.lang.Thread$State;, BLOCKED, null, 49}\n" +
+ "NEW[FIELD_REF]{State.NEW, Ljava.lang.Thread$State;, Ljava.lang.Thread$State;, NEW, null, 49}\n" +
+ "RUNNABLE[FIELD_REF]{State.RUNNABLE, Ljava.lang.Thread$State;, Ljava.lang.Thread$State;, RUNNABLE, null, 49}\n" +
+ "TERMINATED[FIELD_REF]{State.TERMINATED, Ljava.lang.Thread$State;, Ljava.lang.Thread$State;, TERMINATED, null, 49}\n" +
+ "TIMED_WAITING[FIELD_REF]{State.TIMED_WAITING, Ljava.lang.Thread$State;, Ljava.lang.Thread$State;, TIMED_WAITING, null, 49}\n" +
+ "WAITING[FIELD_REF]{State.WAITING, Ljava.lang.Thread$State;, Ljava.lang.Thread$State;, WAITING, null, 49}\n" +
+ "defaultState[METHOD_REF]{defaultState(), LBug443091;, ()Ljava.lang.Thread$State;, defaultState, null, 52}\n" +
+ "forEach[METHOD_REF]{, LBug443091;, (Ljava.util.function.Consumer<Ljava.lang.Integer;>;Ljava.lang.Thread$State;)V, forEach, (in, state), 56}\n" +
+ "forEach[METHOD_REF]{, LBug443091;, (Ljava.util.function.Consumer<Ljava.lang.Integer;>;Ljava.lang.Thread$State;Ljava.lang.Integer;)V, forEach, (in, state, limit), 56}",
+ result);
+ assertTrue("expected type signatures don't match", CharOperation.equals(requestor.getExpectedTypesSignatures(), new char[][] {"Ljava.lang.Thread$State;".toCharArray()}, true));
+}
+public void testBug443091_expectLambdaCompletions_forFunctionalInterfaceArgumentAssignment() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Bug443091.java",
+ "import java.util.function.Consumer;\n" +
+ "\n" +
+ "public class Bug443091 {\n" +
+ " private void foo() {\n" +
+ " forEach(capture)" +
+ " }\n" +
+ " private void forEach(Consumer<Integer> in) {}\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "forEach(";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ String result = requestor.getResults();
+ assertResults("forEach[METHOD_REF]{, LBug443091;, (Ljava.util.function.Consumer<Ljava.lang.Integer;>;)V, forEach, (in), 56}\n"
+ + "[LAMBDA_EXPRESSION]{->, Ljava.util.function.Consumer<Ljava.lang.Integer;>;, (Ljava.lang.Integer;)V, accept, (t), 89}",
+ result);
+}
+public void testBug443091_expectLambdaCompletions_forFunctionalInterfaceVariableAssigments() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Bug443091.java",
+ "import java.util.function.Consumer;\n" +
+ "\n" +
+ "public class Bug443091 {\n" +
+ " private void foo() {\n" +
+ " Consumer<Integer> in = \n" +
+ " }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "in =";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ String result = requestor.getResults();
+ assertResults("finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 47}\n"
+ + "foo[METHOD_REF]{foo(), LBug443091;, ()V, foo, null, 47}\n"
+ + "notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 47}\n"
+ + "notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 47}\n"
+ + "wait[METHOD_REF]{wait(), Ljava.lang.Object;, ()V, wait, null, 47}\n"
+ + "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (J)V, wait, (millis), 47}\n"
+ + "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, wait, (millis, nanos), 47}\n"
+ + "Bug443091[TYPE_REF]{Bug443091, , LBug443091;, null, null, 52}\n"
+ + "clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 52}\n"
+ + "equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 52}\n"
+ + "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<*>;, getClass, null, 52}\n"
+ + "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 52}\n"
+ + "toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 52}\n"
+ + "Consumer<java.lang.Integer>[TYPE_REF]{Consumer, java.util.function, Ljava.util.function.Consumer<Ljava.lang.Integer;>;, null, null, 82}\n"
+ + "[LAMBDA_EXPRESSION]{->, Ljava.util.function.Consumer<Ljava.lang.Integer;>;, (Ljava.lang.Integer;)V, accept, (t), 89}",
+ result);
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java
index 9ac305f..ae1ae06 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java
@@ -6489,4 +6489,110 @@
deleteProject("P");
}
}
+public void testBug575562_AccessRestrictionCheck_ENABLED() throws Exception {
+ Hashtable oldOptions = JavaCore.getOptions();
+ try {
+ Hashtable options = new Hashtable(oldOptions);
+ options.put(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, JavaCore.ERROR);
+ options.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.ENABLED);
+ options.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
+ JavaCore.setOptions(options);
+ setUpJavaProject("AccessRestrictions", "1.4", false);
+ createJavaProject(
+ "P1",
+ new String[] {"src"},
+ new String[] {"JCL_LIB", "/AccessRestrictions/lib.jar"},
+ new String[][]{{}, {}},
+ new String[][]{{}, {"**/*"}},
+ null/*no project*/,
+ null/*no inclusion pattern*/,
+ null/*no exclusion pattern*/,
+ null/*no exported project*/,
+ "bin",
+ null/*no source outputs*/,
+ null/*no inclusion pattern*/,
+ null/*no exclusion pattern*/,
+ "1.4");
+ this.createFolder("/P1/src/p11");
+ this.createFile(
+ "/P1/src/p11/Y11.java",
+ "package p11;\n"+
+ "public class YY11 {\n"+
+ " void foo() {\n"+
+ " X\n"+
+ " }\n"+
+ "}");
+ waitUntilIndexesReady();
+
+ // do completion
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2();
+ ICompilationUnit cu= getCompilationUnit("P1", "src", "p11", "Y11.java");
+
+ String str = cu.getSource();
+ String completeBehind = "X";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ cu.codeComplete(cursorLocation, requestor);
+
+ assertResults(
+ "",
+ requestor.getResults());
+ } finally {
+ this.deleteProject("AccessRestrictions");
+ this.deleteProject("P1");
+ JavaCore.setOptions(oldOptions);
+ }
+}
+public void testBug575562_AccessRestrictionCheck_DISABLED() throws Exception {
+ Hashtable oldOptions = JavaCore.getOptions();
+ try {
+ Hashtable options = new Hashtable(oldOptions);
+ options.put(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, JavaCore.ERROR);
+ options.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.DISABLED);
+ options.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
+ JavaCore.setOptions(options);
+ setUpJavaProject("AccessRestrictions", "1.4", false);
+ createJavaProject(
+ "P1",
+ new String[] {"src"},
+ new String[] {"JCL_LIB", "/AccessRestrictions/lib.jar"},
+ new String[][]{{}, {}},
+ new String[][]{{}, {"**/*"}},
+ null/*no project*/,
+ null/*no inclusion pattern*/,
+ null/*no exclusion pattern*/,
+ null/*no exported project*/,
+ "bin",
+ null/*no source outputs*/,
+ null/*no inclusion pattern*/,
+ null/*no exclusion pattern*/,
+ "1.4");
+ this.createFolder("/P1/src/p11");
+ this.createFile(
+ "/P1/src/p11/Y11.java",
+ "package p11;\n"+
+ "public class YY11 {\n"+
+ " void foo() {\n"+
+ " X\n"+
+ " }\n"+
+ "}");
+ waitUntilIndexesReady();
+
+ // do completion
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2();
+ ICompilationUnit cu= getCompilationUnit("P1", "src", "p11", "Y11.java");
+
+ String str = cu.getSource();
+ String completeBehind = "X";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ cu.codeComplete(cursorLocation, requestor);
+
+ assertResults(
+ "X[TYPE_REF]{p.X, p, Lp.X;, null, 50}",
+ requestor.getResults());
+ } finally {
+ this.deleteProject("AccessRestrictions");
+ this.deleteProject("P1");
+ JavaCore.setOptions(oldOptions);
+ }
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java
index d6b8dd6..a18ac50 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java
@@ -1190,6 +1190,7 @@
int cursorLocation = str.indexOf(completeAfter) + completeAfter.length();
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
assertResults(
+ "class[FIELD_REF]{class, null, Ljava.lang.Class<LThread;>;, class, null, 51}\n" +
"sleep[METHOD_REF]{sleep(), LThread;, (I)V, sleep, (millis), 51}",
requestor.getResults());
} finally {
@@ -1255,6 +1256,7 @@
"serialVersionUID[FIELD_REF]{serialVersionUID, Ljava.lang.Enum<LThread$State;>;, J, serialVersionUID, null, 49}\n" +
"BLOCKED[FIELD_REF]{BLOCKED, LThread$State;, LThread$State;, BLOCKED, null, 51}\n" +
"NEW[FIELD_REF]{NEW, LThread$State;, LThread$State;, NEW, null, 51}\n" +
+ "class[FIELD_REF]{class, null, Ljava.lang.Class<LThread$State;>;, class, null, 51}\n" +
"valueOf[METHOD_REF]{valueOf(), LThread$State;, (Ljava.lang.String;)LThread$State;, valueOf, (arg0), 51}\n" +
"values[METHOD_REF]{values(), LThread$State;, ()[LThread$State;, values, null, 51}",
requestor.getResults());
@@ -1262,4 +1264,259 @@
deleteProject("P");
}
}
+public void testBug575631_comment0() throws Exception {
+ try {
+ createJavaProject("P", new String[] {"src"}, new String[]{"JCL11_LIB"}, "bin", "11");
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/P/src/ContentAssist.java",
+ "import java.util.Calendar;\n" +
+ "class ZoneId {}\n" +
+ "class LocalDateTime {\n" +
+ " static LocalDateTime now() { return null; }\n" +
+ " static LocalDateTime now(ZoneId id) { return null; }\n" +
+ "}\n" +
+ "public class ContentAssist {\n" +
+ " public static void staticMethod() {\n" +
+ " if (true) {\n" +
+ " LocalDateTime.now\n" +
+ " Calendar calendar = Calendar.getInstance();\n" +
+ " }\n" +
+ " }\n" +
+ "}\n");
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ String str = this.workingCopies[0].getSource();
+ String completeAfter = "LocalDateTime.now";
+ int cursorLocation = str.indexOf(completeAfter) + completeAfter.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "now[METHOD_REF]{now(), LLocalDateTime;, ()LLocalDateTime;, now, null, 55}\n" +
+ "now[METHOD_REF]{now(), LLocalDateTime;, (LZoneId;)LLocalDateTime;, now, (id), 55}",
+ requestor.getResults());
+ } finally {
+ deleteProject("P");
+ }
+}
+public void testBug575631_comment1a() throws Exception {
+ try {
+ createJavaProject("P", new String[] {"src"}, new String[]{"JCL11_LIB"}, "bin", "11");
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/P/src/missing_proposals_for_static_fields_and_methods.java",
+ "\n" +
+ "class System {\n" +
+ " static Object out;\n" +
+ " static Object getEnv() { return null; }\n" +
+ "}\n" +
+ "class missing_proposals_for_static_fields_and_methods {\n" +
+ " void sample(String foo) {\n" +
+ " if (foo == null) {\n" +
+ " System. // <- missing: \"out\", \"getenv()\", etc. (similar to bug 574267)\n" +
+ " System.out.println();\n" +
+ " }\n" +
+ " System. // <- here content assist works fine\n" +
+ " }\n" +
+ "}\n");
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ String str = this.workingCopies[0].getSource();
+ String completeAfter = "System.";
+ int cursorLocation = str.indexOf(completeAfter) + completeAfter.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "class[FIELD_REF]{class, null, Ljava.lang.Class<LSystem;>;, class, null, 51}\n" +
+ "getEnv[METHOD_REF]{getEnv(), LSystem;, ()Ljava.lang.Object;, getEnv, null, 51}\n" +
+ "out[FIELD_REF]{out, LSystem;, Ljava.lang.Object;, out, null, 51}",
+ requestor.getResults());
+ } finally {
+ deleteProject("P");
+ }
+}
+public void testBug575631_comment1b() throws Exception {
+ try {
+ createJavaProject("P", new String[] {"src"}, new String[]{"JCL11_LIB"}, "bin", "11");
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/P/src/missing_proposals_for_static_fields_and_methods.java",
+ "\n" +
+ "class System {\n" +
+ " static Object out;\n" +
+ " static Object getEnv() { return null; }\n" +
+ "}\n" +
+ "class missing_proposals_for_static_fields_and_methods {\n" +
+ " void sample(String foo) {\n" +
+ " if (foo == null) {\n" +
+ " sample(\"\");\n" +
+ " } else {\n" +
+ " System. // <- missing: \"out\", \"getenv()\", etc. (similar to bug 574215)\n" +
+ " System.out.println();\n" +
+ " }\n" +
+ " System. // <- here content assist works fine\n" +
+ " }\n" +
+ "}\n");
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ String str = this.workingCopies[0].getSource();
+ String completeAfter = "System.";
+ int cursorLocation = str.indexOf(completeAfter) + completeAfter.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "class[FIELD_REF]{class, null, Ljava.lang.Class<LSystem;>;, class, null, 51}\n" +
+ "getEnv[METHOD_REF]{getEnv(), LSystem;, ()Ljava.lang.Object;, getEnv, null, 51}\n" +
+ "out[FIELD_REF]{out, LSystem;, Ljava.lang.Object;, out, null, 51}",
+ requestor.getResults());
+ } finally {
+ deleteProject("P");
+ }
+}
+public void testBug575631_comment3() throws Exception {
+ try {
+ createJavaProject("P", new String[] {"src"}, new String[]{"JCL11_LIB"}, "bin", "11");
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/P/src/X.java",
+ "class OutputStream {\n" +
+ " void println() {}\n" +
+ "}\n" +
+ "interface Runnable { void run(); }\n" +
+ "class System {\n" +
+ " static OutputStream out;\n" +
+ " static Object getEnv() { return null; }\n" +
+ "}\n" +
+ "class X {\n" +
+ " void foo() {\n" +
+ " Runnable r = () -> {\n" +
+ " System.out.\n" +
+ " System.out.println();\n" +
+ " };\n" +
+ " }\n" +
+ "}\n");
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ String str = this.workingCopies[0].getSource();
+ String completeAfter = "System.out.";
+ int cursorLocation = str.indexOf(completeAfter) + completeAfter.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 60}\n" +
+ "equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 60}\n" +
+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 60}\n" +
+ "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, 60}\n" +
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 60}\n" +
+ "notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 60}\n" +
+ "notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 60}\n" +
+ "println[METHOD_REF]{println(), LOutputStream;, ()V, println, null, 60}\n" +
+ "toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 60}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, ()V, wait, null, 60}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (J)V, wait, (millis), 60}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, wait, (millis, nanos), 60}",
+ requestor.getResults());
+ } finally {
+ deleteProject("P");
+ }
+}
+public void testBug575631_comment3b() throws Exception {
+ // method invocation inside lambda in field initializer
+ try {
+ createJavaProject("P", new String[] {"src"}, new String[]{"JCL11_LIB"}, "bin", "11");
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/P/src/X.java",
+ "class OutputStream {\n" +
+ " void println() {}\n" +
+ "}\n" +
+ "interface Runnable { void run(); }\n" +
+ "class System {\n" +
+ " static OutputStream out;\n" +
+ " static Object getEnv() { return null; }\n" +
+ "}\n" +
+ "class X {\n" +
+ " Runnable r = () -> {\n" +
+ " System.out.\n" +
+ " System.out.println();\n" +
+ " };\n" +
+ "}\n");
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ String str = this.workingCopies[0].getSource();
+ String completeAfter = "System.out.";
+ int cursorLocation = str.indexOf(completeAfter) + completeAfter.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 60}\n" +
+ "equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 60}\n" +
+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 60}\n" +
+ "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, 60}\n" +
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 60}\n" +
+ "notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 60}\n" +
+ "notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 60}\n" +
+ "println[METHOD_REF]{println(), LOutputStream;, ()V, println, null, 60}\n" +
+ "toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 60}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, ()V, wait, null, 60}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (J)V, wait, (millis), 60}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, wait, (millis, nanos), 60}",
+ requestor.getResults());
+ } finally {
+ deleteProject("P");
+ }
+}
+public void testBug575631_comment3c() throws Exception {
+ // variable declaration in lambda in field initializer
+ try {
+ createJavaProject("P", new String[] {"src"}, new String[]{"JCL11_LIB"}, "bin", "11");
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/P/src/X.java",
+ "class OutputStream {\n" +
+ " void println() {}\n" +
+ "}\n" +
+ "interface Consumer { void consume(int); }\n" +
+ "class Number{}\n" +
+ "class System {\n" +
+ " static OutputStream out;\n" +
+ " static Object getEnv() { return null; }\n" +
+ "}\n" +
+ "class X {\n" +
+ " Consumer r = (int number) -> {\n" +
+ " Number \n" +
+ " System.out.println();\n" +
+ " };\n" +
+ "}\n");
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ String str = this.workingCopies[0].getSource();
+ String completeAfter = "Number ";
+ int cursorLocation = str.indexOf(completeAfter) + completeAfter.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "number[VARIABLE_DECLARATION]{number, null, LNumber;, number, null, 48}", // FIXME: should be number2 => https://bugs.eclipse.org/576781
+ requestor.getResults());
+ } finally {
+ deleteProject("P");
+ }
+}
+public void testBug575631_comment3d() throws Exception {
+ // first of two arguments in method invocation in lambda in field initializer
+ // overloads should be selected by the existing second argument
+ // no separating ',' yet.
+ try {
+ createJavaProject("P", new String[] {"src"}, new String[]{"JCL11_LIB"}, "bin", "11");
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/P/src/X.java",
+ "interface BiConsumer { void consume(int,boolean); }\n" +
+ "class X {\n" +
+ " BiConsumer r = (int number, boolean bool) -> {\n" +
+ " bar( number);\n" +
+ " };\n" +
+ " void bar(int i, String s) {}\n" +
+ " void bar(boolean b, int j) {}\n" +
+ "}\n");
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ String str = this.workingCopies[0].getSource();
+ String completeAfter = "bar(";
+ int cursorLocation = str.indexOf(completeAfter) + completeAfter.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "bar[METHOD_REF]{, LX;, (ZI)V, bar, (b, j), 56}", // select overload with int as 2nd arg
+ requestor.getResults());
+ } finally {
+ deleteProject("P");
+ }
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTestsRequestor2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTestsRequestor2.java
index 072cbe5..48a203c 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTestsRequestor2.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTestsRequestor2.java
@@ -438,6 +438,9 @@
case CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION :
buffer.append("ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION"); //$NON-NLS-1$
break;
+ case CompletionProposal.LAMBDA_EXPRESSION :
+ buffer.append("LAMBDA_EXPRESSION"); //$NON-NLS-1$
+ break;
default :
buffer.append("PROPOSAL"); //$NON-NLS-1$
break;
@@ -709,4 +712,8 @@
}
return null;
}
+
+ public char[][] getExpectedTypesSignatures() {
+ return this.context.getExpectedTypesSignatures();
+ }
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java
index a3962cb..44b9319 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java
@@ -11609,6 +11609,7 @@
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
assertResults(
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_UNQUALIFIED + R_NON_RESTRICTED) + "}\n" +
"get[METHOD_REF]{, Ltest.util.List<Ljava.lang.String;>;, (I)Ljava.lang.String;, get, (i), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME + R_UNQUALIFIED + R_NON_RESTRICTED) + "}",
requestor.getResults());
}
@@ -11676,6 +11677,7 @@
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
assertResults(
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_UNQUALIFIED + R_NON_RESTRICTED) + "}\n" +
"abs[METHOD_REF]{, Ltest.util.Math;, (I)I, abs, (i), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME + R_UNQUALIFIED + R_NON_RESTRICTED) + "}",
requestor.getResults());
}
@@ -11706,6 +11708,7 @@
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
assertResults(
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_UNQUALIFIED + R_NON_RESTRICTED) + "}\n" +
"abs[METHOD_REF]{, Ltest.util.Math;, (I)I, abs, (i), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME + R_UNQUALIFIED + R_NON_RESTRICTED) + "}",
requestor.getResults());
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExclusionPatternsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExclusionPatternsTests.java
index 028b7ad..0222e0d 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExclusionPatternsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExclusionPatternsTests.java
@@ -435,6 +435,8 @@
ICompilationUnit cu = getCompilationUnit("/P/src/p/A.java");
assertTrue("CU should be on classpath", this.project.isOnClasspath(cu));
+
+ assertResourceOnClasspathEntry(this.project, file, "/P/src");
}
/*
* Ensures that a cu that is excluded is not on the classpath of the project.
@@ -450,6 +452,8 @@
);
assertTrue("Resource should not be on classpath", !this.project.isOnClasspath(file));
+ assertResourceNotOnClasspathEntry(this.project, file);
+
ICompilationUnit cu = getCompilationUnit("/P/src/p/A.java");
assertTrue("CU should not be on classpath", !this.project.isOnClasspath(cu));
}
@@ -461,6 +465,8 @@
createFolder("/P/src/p");
IFile file = createFile("/P/src/p/readme.txt", "");
assertTrue("Resource should be on classpath", this.project.isOnClasspath(file));
+
+ assertResourceOnClasspathEntry(this.project, file, "/P/src");
}
/*
* Ensures that a non-java resource that is excluded is not on the classpath of the project.
@@ -470,6 +476,8 @@
createFolder("/P/src/p");
IFile file = createFile("/P/src/p/readme.txt", "");
assertTrue("Resource should not be on classpath", !this.project.isOnClasspath(file));
+
+ assertResourceNotOnClasspathEntry(this.project, file);
}
/*
* Ensures that an excluded nested source folder doesn't appear as a non-java resource of the outer folder.
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/InclusionPatternsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/InclusionPatternsTests.java
index 5d2c0ba..19c2b40 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/InclusionPatternsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/InclusionPatternsTests.java
@@ -537,6 +537,8 @@
);
assertTrue("Resource should not be on classpath", !this.project.isOnClasspath(file));
+ assertResourceNotOnClasspathEntry(this.project, file);
+
ICompilationUnit cu = getCompilationUnit("/P/src/p/A.java");
assertTrue("CU should not be on classpath", !this.project.isOnClasspath(cu));
}
@@ -554,6 +556,8 @@
);
assertTrue("Resource should be on classpath", this.project.isOnClasspath(file));
+ assertResourceOnClasspathEntry(this.project, file, "/P/src");
+
ICompilationUnit cu = getCompilationUnit("/P/src/p/A.java");
assertTrue("CU should be on classpath", this.project.isOnClasspath(cu));
}
@@ -565,6 +569,7 @@
createFolder("/P/src/p");
IFile file = createFile("/P/src/p/readme.txt", "");
assertTrue("Resource should not be on classpath", !this.project.isOnClasspath(file));
+ assertResourceNotOnClasspathEntry(this.project, file);
}
/*
* Ensures that a non-java resource that is included is on the classpath of the project.
@@ -574,6 +579,7 @@
createFolder("/P/src/p");
IFile file = createFile("/P/src/p/readme.txt", "");
assertTrue("Resource should be on classpath", this.project.isOnClasspath(file));
+ assertResourceOnClasspathEntry(this.project, file, "/P/src");
}
/*
* Ensures that moving a folder that contains an included package reports the correct delta.
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests16.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests16.java
index bdc8992..1eb2ece 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests16.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests16.java
@@ -193,4 +193,62 @@
deleteProject(p);
}
}
+public void testBug576448_001() throws Exception {
+ if (!isJRE16)
+ return;
+ IJavaProject p = createJava16Project("p");
+ createFolder("/p/src/a");
+ try {
+ createFile("p/src/a/X.java",
+ "package a;\n"+
+ "import a.Interface.NestedInterface;\n"+
+ "import a.Interface.NestedInterface2;\n"+
+ "\n"+
+ "public record X(String someString, NestedInterface someInterface) implements NestedInterface2 {\n"+
+ " public X(NestedInterface someInterface) {\n"+
+ " this(null, someInterface); // <- error here\n"+
+ " }\n"+
+ " public X(String someString, NestedInterface someInterface) {\n"+
+ " this.someString = someString;\n"+
+ " this.someInterface = someInterface;\n"+
+ " }\n"+
+ " public static void main(String[] args) {\n"+
+ " System.out.println(\"hello\");\n"+
+ " }\n"+
+ "}");
+ createFile("p/src/a/Interface.java",
+ "package a;\n"+
+ "public interface Interface {\n"+
+ " interface NestedInterface {\n"+
+ " }\n"+
+ " interface NestedInterface2 {\n"+
+ " String someString();\n"+
+ " NestedInterface someInterface();\n"+
+ " static NestedInterface2 create(String s, NestedInterface n) {\n"+
+ " return new X(s, n);\n"+
+ " }\n"+
+ " static NestedInterface2 create(NestedInterface n) {\n"+
+ " return new X(n);\n"+
+ " }\n"+
+ " }\n"+
+ "}");
+
+ p.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
+ IMarker[] markers = p.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+ assertMarkers("markers in p",
+ "",
+ markers);
+
+ this.workingCopy = getCompilationUnit("p/src/X.java").getWorkingCopy(this.wcOwner, null);
+ this.problemRequestor.initialize(this.workingCopy.getSource().toCharArray());
+ this.workingCopy.reconcile(JLS_LATEST, true, this.wcOwner, null);
+ assertProblems("Expecting no problems",
+ "----------\n" +
+ "----------\n",
+ this.problemRequestor);
+ this.workingCopy.discardWorkingCopy();
+ } finally {
+ deleteProject(p);
+ }
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SubwordCompletionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SubwordCompletionTests.java
index d377304..a6e8043 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SubwordCompletionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SubwordCompletionTests.java
@@ -897,6 +897,7 @@
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
assertResults(
+ "toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_UNQUALIFIED + R_NON_RESTRICTED ) + "}\n" +
"put[METHOD_REF]{, Ljava.util.Map<Ljava.lang.String;Ljava.lang.String;>;, (Ljava.lang.String;Ljava.lang.String;)Ljava.lang.String;, put, (key, value), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_EXACT_NAME + R_CASE + R_UNQUALIFIED + R_NON_RESTRICTED ) + "}",
requestor.getResults());
}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/.classpath b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/.classpath
new file mode 100644
index 0000000..e22b721
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="lib" path="lib/bug565512.jar" rootpath=""/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/.project b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/.project
new file mode 100644
index 0000000..aa4d11d
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>JavaSearchBug565512lib</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/bin/dummy/Dummy.class b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/bin/dummy/Dummy.class
new file mode 100644
index 0000000..4faf163
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/bin/dummy/Dummy.class
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/lib/bug565512.jar b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/lib/bug565512.jar
new file mode 100644
index 0000000..005540a
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/lib/bug565512.jar
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/src/dummy/Dummy.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/src/dummy/Dummy.java
new file mode 100644
index 0000000..44de296
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/src/dummy/Dummy.java
@@ -0,0 +1,12 @@
+package dummy;
+
+public class Dummy {
+
+ // note that "String" implicit means "java.lang.String":
+ public static void main(String[] args) {
+ }
+// // TODO: somehow it makes a difference during search if "java.lang.String" is used in the class:
+ //bug 576306
+ void any(java.lang.String[] a) {
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.classpath b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.classpath
new file mode 100644
index 0000000..f31482b
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="lib" path="lib/bug565512Module.jar"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
+ <attributes>
+ <attribute name="module" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.project b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.project
new file mode 100644
index 0000000..62020e3
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>JavaSearchBug565512libModule</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..a58ebdc
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,15 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/bin/dummy/Dummy.class b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/bin/dummy/Dummy.class
new file mode 100644
index 0000000..4faf163
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/bin/dummy/Dummy.class
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/lib/bug565512Module.jar b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/lib/bug565512Module.jar
new file mode 100644
index 0000000..655a51e
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/lib/bug565512Module.jar
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/src/dummy/Dummy.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/src/dummy/Dummy.java
new file mode 100644
index 0000000..44de296
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/src/dummy/Dummy.java
@@ -0,0 +1,12 @@
+package dummy;
+
+public class Dummy {
+
+ // note that "String" implicit means "java.lang.String":
+ public static void main(String[] args) {
+ }
+// // TODO: somehow it makes a difference during search if "java.lang.String" is used in the class:
+ //bug 576306
+ void any(java.lang.String[] a) {
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.classpath b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.classpath
new file mode 100644
index 0000000..33c97a3
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.classpath
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
+ <attributes>
+ <attribute name="module" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.gitignore b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.project b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.project
new file mode 100644
index 0000000..69f9b49
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.project
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>bug565512</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+ <linkedResources>
+ <link>
+ <name>src</name>
+ <type>2</type>
+ <locationURI>$%257BPARENT-2-PROJECT_LOC%257D/JavaSearchBug565512src/src</locationURI>
+ </link>
+ </linkedResources>
+</projectDescription>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..cd8d089
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,15 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/export bug565512.jar.jardesc b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/export bug565512.jar.jardesc
new file mode 100644
index 0000000..355ce27
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/export bug565512.jar.jardesc
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?>
+<jardesc>
+ <jar path="org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512lib/lib/bug565512.jar"/>
+ <options buildIfNeeded="true" compress="true" descriptionLocation="/bug565512/export bug565512.jar.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+ <storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+ <selectedProjects/>
+ <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+ <sealing sealJar="false">
+ <packagesToSeal/>
+ <packagesToUnSeal/>
+ </sealing>
+ </manifest>
+ <selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
+ <javaElement handleIdentifier="=bug565512/src"/>
+ </selectedElements>
+</jardesc>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/export bug565512WithSrc.jar.jardesc b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/export bug565512WithSrc.jar.jardesc
new file mode 100644
index 0000000..b408f36
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512/export bug565512WithSrc.jar.jardesc
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?>
+<jardesc>
+ <jar path="org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/lib/bug565512WithSrc.jar"/>
+ <options buildIfNeeded="true" compress="true" descriptionLocation="/bug565512/export bug565512WithSrc.jar.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+ <storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+ <selectedProjects/>
+ <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+ <sealing sealJar="false">
+ <packagesToSeal/>
+ <packagesToUnSeal/>
+ </sealing>
+ </manifest>
+ <selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false">
+ <javaElement handleIdentifier="=bug565512/src"/>
+ </selectedElements>
+</jardesc>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.classpath b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.classpath
new file mode 100644
index 0000000..19d5e94
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="src2"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
+ <attributes>
+ <attribute name="module" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.gitignore b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.project b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.project
new file mode 100644
index 0000000..9998c14
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.project
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>bug565512Module</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+ <linkedResources>
+ <link>
+ <name>src</name>
+ <type>2</type>
+ <locationURI>$%257BPARENT-2-PROJECT_LOC%257D/JavaSearchBug565512src/src</locationURI>
+ </link>
+ </linkedResources>
+</projectDescription>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..a58ebdc
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,15 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/export bug565512Module.jar.jardesc b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/export bug565512Module.jar.jardesc
new file mode 100644
index 0000000..0b83220
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/export bug565512Module.jar.jardesc
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?>
+<jardesc>
+ <jar path="org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libModule/lib/bug565512Module.jar"/>
+ <options buildIfNeeded="true" compress="true" descriptionLocation="/bug565512Module/export bug565512Module.jar.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+ <storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+ <selectedProjects/>
+ <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+ <sealing sealJar="false">
+ <packagesToSeal/>
+ <packagesToUnSeal/>
+ </sealing>
+ </manifest>
+ <selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
+ <javaElement handleIdentifier="=bug565512Module/src"/>
+ <javaElement handleIdentifier="=bug565512Module/src2"/>
+ </selectedElements>
+</jardesc>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/src2/module-info.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/src2/module-info.java
new file mode 100644
index 0000000..9b2b4c5
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libProjects/bug565512Module/src2/module-info.java
@@ -0,0 +1,2 @@
+module bug565512 {
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/.classpath b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/.classpath
new file mode 100644
index 0000000..bcb39f4
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="lib" path="lib/bug565512WithSrc.jar" rootpath=""/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/.project b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/.project
new file mode 100644
index 0000000..0a1dbac
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>JavaSearchBug565512libWithSrc</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/bin/dummy/Dummy.class b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/bin/dummy/Dummy.class
new file mode 100644
index 0000000..4faf163
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/bin/dummy/Dummy.class
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/lib/bug565512WithSrc.jar b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/lib/bug565512WithSrc.jar
new file mode 100644
index 0000000..c22b9ce
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/lib/bug565512WithSrc.jar
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/src/dummy/Dummy.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/src/dummy/Dummy.java
new file mode 100644
index 0000000..44de296
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512libWithSrc/src/dummy/Dummy.java
@@ -0,0 +1,12 @@
+package dummy;
+
+public class Dummy {
+
+ // note that "String" implicit means "java.lang.String":
+ public static void main(String[] args) {
+ }
+// // TODO: somehow it makes a difference during search if "java.lang.String" is used in the class:
+ //bug 576306
+ void any(java.lang.String[] a) {
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.classpath b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.classpath
new file mode 100644
index 0000000..fb50116
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.gitignore b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.gitignore
new file mode 100644
index 0000000..ae3c172
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.project b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.project
new file mode 100644
index 0000000..f9323b6
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>JavaSearchBug565512src</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/$/$/$.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/$/$/$.java
new file mode 100644
index 0000000..2bbd1c2
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/$/$/$.java
@@ -0,0 +1,48 @@
+package $.$;
+
+class $ { // $.$.$
+ int $; // $.$.$.$
+ void $() {} // $.$.$.$()
+ class $I { // $.$.$.$I
+ int $; // $.$.$.$I.$
+ void $() {} // $.$.$.$I.$()
+ class $II { // $.$.$.$I.$II
+ int $; // $.$.$.$I.$II.$
+ void $() {} // $.$.$.$I.$II.$()
+ }
+ }
+ static class $SI { // $.$.$.$SI
+ int $; // $.$.$.$SI.$
+ void $() {} // $.$.$.$SI.$()
+ static class $SII { // $.$.$.$SI.$SII
+ int $; // $.$.$.$SI.$SII.$
+ void $() {} // $.$.$.$SI.$SII.$()
+ }
+ }
+
+ class $E extends $ { // $.$.$.$E
+ int $; // $.$.$.$E.$
+ void $() {} // $.$.$.$E.$()
+ class $EE extends $E { // $.$.$.$E.$EE
+ int $; // $.$.$.$E.$EE.$
+ void $() {} // $.$.$.$E.$EE.$()
+ }
+ }
+ static class $SE extends $ {// $.$.$.$SE
+ int $; // $.$.$.$SE.$
+ void $() {} // $.$.$.$E.$()
+ static class $SEE extends $SE { // $.$.$.$SE.$SEE
+ int $; // $.$.$.$SE.$SEE.$
+ void $() { // $.$.$.$SE.$SEE.$()
+ new $().$();
+ (new $().new $I()).$();
+ (new $().new $I().new $II()).$();
+ new $SI().$();
+ (new $SI.$SII()).$();
+ new $SE().$();
+ (new $SE.$SEE()).$();
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512/Class565512.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512/Class565512.java
new file mode 100644
index 0000000..8099324
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512/Class565512.java
@@ -0,0 +1,98 @@
+package lib565512;
+
+//this class has references itself
+public class Class565512 {
+ class InnerClass {
+ class InnerClass2 {
+ }
+ }
+
+ static class StaticNestedClass {
+ static class StaticNestedClass2 {
+ }
+ }
+
+ { class LocalClass {{ class LocalClass2 {}}}
+ new Class565512() {// Anonymous
+ {new Class565512() {// Anonymous2
+ };
+ }
+ };
+ }
+ public static class PublicStaticInnerClass {}
+ private class PrivateInnerClass {}
+ private static class PrivateStaticInnerClass {}
+
+ public class ExtendedClass extends Class565512 {}
+ public class ExtendedInnerClass extends InnerClass {}
+ static class ExtendedPublicStaticInnerClass extends PublicStaticInnerClass {}
+ private class ExtendedPrivateInnerClass extends PrivateInnerClass {}
+ private static class ExtendedPrivateStaticInnerClass extends PrivateStaticInnerClass {}
+
+ void inside(Class565512 c) {
+ class InnerClassInside {
+ class InnerClass2Inside {
+ }
+ }
+
+
+ { class LocalClassInside {{ class LocalClass2Inside {}}}
+ new Class565512() {// Anonymous
+ {new Class565512() {// Anonymous2
+ };
+ }
+ };
+ }
+ }
+
+ void x() {
+ x();
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ }
+
+ private static void privateStatic() {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ }
+
+ public static void customMain(String[] args) {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ }
+
+ public static String stringReturning() {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ return null;
+ }
+
+ public static void main(String[] args) {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ }
+
+ public static int primitiveMain(int[] args) {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ return 0;
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512/ExtendedClass565512.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512/ExtendedClass565512.java
new file mode 100644
index 0000000..26435e6
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512/ExtendedClass565512.java
@@ -0,0 +1,59 @@
+package lib565512;
+
+//this class has references to lib565512.Class565512
+public class ExtendedClass565512 extends Class565512{
+ class InnerClass {}
+ public static class PublicStaticInnerClass {}
+ private class PrivateInnerClass {}
+ private static class PrivateStaticInnerClass {}
+
+ public class ExtendedClass extends Class565512 {}
+ public class ExtendedInnerClass extends Class565512.InnerClass {}
+ static class ExtendedPublicStaticInnerClass extends Class565512.PublicStaticInnerClass {}
+
+ void x() {
+ Class565512 c = new Class565512();
+ c.x();
+ c.main(null);
+ c.customMain(null);
+ c.primitiveMain(null);
+ c.stringReturning();
+ }
+
+ private static void privateStatic() {
+ Class565512.main(null);
+ Class565512.customMain(null);
+ Class565512.primitiveMain(null);
+ Class565512.stringReturning();
+ }
+
+ public static void customMain(String[] args) {
+ Class565512.main(null);
+ Class565512.customMain(null);
+ Class565512.primitiveMain(null);
+ Class565512.stringReturning();
+ }
+
+ public static String stringReturning() {
+ Class565512.main(null);
+ Class565512.customMain(null);
+ Class565512.primitiveMain(null);
+ Class565512.stringReturning();
+ return null;
+ }
+
+ public static void main(String[] args) {
+ Class565512.main(null);
+ Class565512.customMain(null);
+ Class565512.primitiveMain(null);
+ Class565512.stringReturning();
+ }
+
+ public static int primitiveMain(int[] args) {
+ Class565512.main(null);
+ Class565512.customMain(null);
+ Class565512.primitiveMain(null);
+ Class565512.stringReturning();
+ return 0;
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512wrong/Class565512.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512wrong/Class565512.java
new file mode 100644
index 0000000..85ba385
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512wrong/Class565512.java
@@ -0,0 +1,67 @@
+package lib565512wrong;
+
+// this class has no references to lib565512.Class565512
+// but it has the same unqualified name
+public class Class565512 {
+ class InnerClass {}
+ public static class PublicStaticInnerClass {}
+ private class PrivateInnerClass {}
+ private static class PrivateStaticInnerClass {}
+
+ public class ExtendedClass extends Class565512 {}
+ public class ExtendedInnerClass extends InnerClass {}
+ static class ExtendedPublicStaticInnerClass extends PublicStaticInnerClass {}
+ private class ExtendedPrivateInnerClass extends PrivateInnerClass {}
+ private static class ExtendedPrivateStaticInnerClass extends PrivateStaticInnerClass {}
+
+ void x() {
+ x();
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ }
+
+ private static void privateStatic() {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ }
+
+ public static void customMain(String[] args) {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ }
+
+ public static String stringReturning() {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ return null;
+ }
+
+ public static void main(String[] args) {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ }
+
+ public static int primitiveMain(int[] args) {
+ main(null);
+ customMain(null);
+ privateStatic();
+ primitiveMain(null);
+ stringReturning();
+ return 0;
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512wrong/WrongClass565512.java b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512wrong/WrongClass565512.java
new file mode 100644
index 0000000..7bc2ed7
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBug565512src/src/lib565512wrong/WrongClass565512.java
@@ -0,0 +1,36 @@
+package lib565512wrong;
+
+// this class has no references to lib565512.Class565512
+// but it has the same member names
+public class WrongClass565512 {
+ class InnerClass {}
+ public static class PublicStaticInnerClass {}
+ private class PrivateInnerClass {}
+ private static class PrivateStaticInnerClass {}
+
+ public class ExtendedClass extends WrongClass565512 {}
+ public class ExtendedInnerClass extends InnerClass {}
+ static class ExtendedPublicStaticInnerClass extends PublicStaticInnerClass {}
+ private class ExtendedPrivateInnerClass extends PrivateInnerClass {}
+ private static class ExtendedPrivateStaticInnerClass extends PrivateStaticInnerClass {}
+
+ void x() {
+ }
+
+ private static void privateStatic() {
+ }
+
+ public static void customMain(String[] args) {
+ }
+
+ public static String stringReturning() {
+ return null;
+ }
+
+ public static void main(String[] args) {
+ }
+
+ public static int primitiveMain(int[] args) {
+ return 0;
+ }
+}
diff --git a/org.eclipse.jdt.core/.settings/.api_filters b/org.eclipse.jdt.core/.settings/.api_filters
index 91eb28a..d0691df 100644
--- a/org.eclipse.jdt.core/.settings/.api_filters
+++ b/org.eclipse.jdt.core/.settings/.api_filters
@@ -730,6 +730,15 @@
</message_arguments>
</filter>
</resource>
+ <resource path="model/org/eclipse/jdt/core/CompletionProposal.java" type="org.eclipse.jdt.core.CompletionProposal">
+ <filter comment="give way to new constant from JDT" id="388194388">
+ <message_arguments>
+ <message_argument value="org.eclipse.jdt.core.CompletionProposal"/>
+ <message_argument value="OVERRIDE_ROLE_DECLARATION"/>
+ <message_argument value="30"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="model/org/eclipse/jdt/core/Flags.java" type="org.eclipse.jdt.core.Flags">
<filter comment="Must yield to new AccRecord." id="388194388">
<message_arguments>
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index 265eb0d..f1fa3bf 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -2199,36 +2199,6 @@
continue;
}
}
- if (currentArg.equals("-15") || currentArg.equals("-15.0")) { //$NON-NLS-1$ //$NON-NLS-2$
- if (didSpecifyCompliance) {
- throw new IllegalArgumentException(
- this.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
- }
- didSpecifyCompliance = true;
- this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_15);
- mode = DEFAULT;
- continue;
- }
- if (currentArg.equals("-16") || currentArg.equals("-16.0")) { //$NON-NLS-1$ //$NON-NLS-2$
- if (didSpecifyCompliance) {
- throw new IllegalArgumentException(
- this.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
- }
- didSpecifyCompliance = true;
- this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_16);
- mode = DEFAULT;
- continue;
- }
- if (currentArg.equals("-17") || currentArg.equals("-17.0")) { //$NON-NLS-1$ //$NON-NLS-2$
- if (didSpecifyCompliance) {
- throw new IllegalArgumentException(
- this.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
- }
- didSpecifyCompliance = true;
- this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_16);
- mode = DEFAULT;
- continue;
- }
if (currentArg.equals("-d")) { //$NON-NLS-1$
if (this.destinationPath != null) {
StringBuilder errorMessage = new StringBuilder();
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
index b665a01..7206e92 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
@@ -17,6 +17,7 @@
* Stephan Herrmann - Contribution for
* Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
* Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions
+ * Microsoft Corporation - Contribution for bug 575562 - improve completion search performance
*******************************************************************************/
package org.eclipse.jdt.internal.codeassist;
@@ -709,6 +710,7 @@
private final static char[] STATIC = "static".toCharArray(); //$NON-NLS-1$
private final static char[] ON_DEMAND = ".*".toCharArray(); //$NON-NLS-1$
private final static char[] IMPORT_END = ";\n".toCharArray(); //$NON-NLS-1$
+ private final static char[] LAMBDA = "->".toCharArray(); //$NON-NLS-1$
private final static char[] JAVA_LANG_OBJECT_SIGNATURE =
createTypeSignature(CharOperation.concatWith(JAVA_LANG, '.'), OBJECT);
@@ -880,6 +882,15 @@
private int foundConstructorsCount;
private ObjectVector acceptedConstructors;
+ /**
+ * The strictMatchForExtepectedType used to skip all elements found at <code>findVariablesAndMethods</code>
+ * which doesn't match the current expected types in the engine in <code>expectedTypes</code>. Since in this mode
+ * all elements found matches the expected type, the completion proposals will not contains the calculated expected type
+ * relevance. This is done to keep the overloaded method suggestions always on top in this mode as a fix for
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=575149
+ *
+ */
+ private boolean strictMatchForExtepectedType = false;
/**
* The CompletionEngine is responsible for computing source completions.
@@ -2043,11 +2054,15 @@
} else if (astNode instanceof CompletionOnQualifiedNameReference) {
completionOnQualifiedNameReference(astNode, enclosingNode, qualifiedBinding, scope, insideTypeAnnotation);
} else if (astNode instanceof CompletionOnQualifiedTypeReference) {
- completionOnQualifiedTypeReference(astNode, astNodeParent, qualifiedBinding, scope);
+ completionOnQualifiedTypeReference(astNode, astNodeParent, enclosingNode, qualifiedBinding, scope);
} else if (astNode instanceof CompletionOnMemberAccess) {
completionOnMemberAccess(astNode, enclosingNode, qualifiedBinding, scope, insideTypeAnnotation);
} else if (astNode instanceof CompletionOnMessageSend) {
completionOnMessageSend(astNode, qualifiedBinding, scope);
+ // rebuild the context with newly found expected types so other completion computers can benifit from it.
+ if(this.expectedTypesPtr > -1) {
+ buildContext(astNode, astNodeParent, compilationUnitDeclaration, qualifiedBinding, scope);
+ }
//{ObjectTeams: complete rhs method spec in a callout or callin:
} else if (astNode instanceof CompletionOnMethodSpec) {
completionOnMethodSpec(astNode, qualifiedBinding, scope);
@@ -3305,9 +3320,9 @@
CompletionOnMessageSend messageSend = (CompletionOnMessageSend) astNode;
TypeBinding[] argTypes = computeTypes(messageSend.arguments);
this.completionToken = messageSend.selector;
+ ObjectVector methodsFound = new ObjectVector();
if (qualifiedBinding == null) {
if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
- ObjectVector methodsFound = new ObjectVector();
findImplicitMessageSends(this.completionToken, argTypes, scope, messageSend, scope, methodsFound);
@@ -3329,7 +3344,7 @@
argTypes,
(ReferenceBinding)((ReferenceBinding) qualifiedBinding).capture(scope, messageSend.receiver.sourceStart, messageSend.receiver.sourceEnd),
scope,
- new ObjectVector(),
+ methodsFound,
false,
true,
messageSend,
@@ -3345,6 +3360,40 @@
-1,
-1);
}
+
+ findCompletionsForArgumentPosition(methodsFound, argTypes != null ? argTypes.length : 0, scope);
+ }
+
+ private void findCompletionsForArgumentPosition(ObjectVector methodsFound, int completedArgumentLength, Scope scope) {
+ if(methodsFound.size == 0) {
+ return;
+ }
+
+ for(int i = 0; i < methodsFound.size; i++) {
+ MethodBinding method = (MethodBinding) ((Object[])methodsFound.elementAt(i))[0];
+ if(method.parameters.length <= completedArgumentLength) {
+ continue;
+ }
+
+ TypeBinding paramType = method.parameters[completedArgumentLength];
+ addExpectedType(paramType, scope);
+ }
+ this.strictMatchForExtepectedType = true;
+ int filter = this.expectedTypesFilter;
+ this.expectedTypesFilter = SUBTYPE;
+ int start = this.startPosition, end = this.endPosition;
+ int tStart = this.tokenStart, tEnd = this.tokenEnd;
+ try {
+ this.startPosition = this.endPosition = this.tokenStart = this.tokenEnd = this.actualCompletionPosition + 1;
+ findVariablesAndMethods(CharOperation.NO_CHAR, scope, FakeInvocationSite, scope, false, false, false, methodsFound);
+ } finally {
+ this.startPosition = start;
+ this.endPosition = end;
+ this.tokenStart = tStart;
+ this.tokenEnd = tEnd;
+ this.strictMatchForExtepectedType = false;
+ this.expectedTypesFilter = filter;
+ }
}
private void completionOnMessageSendName(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
@@ -3658,8 +3707,15 @@
CompletionOnQualifiedNameReference ref =
(CompletionOnQualifiedNameReference) astNode;
this.completionToken = ref.completionIdentifier;
- long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1];
+ internalCompletionOnQualifiedReference(astNode, enclosingNode, qualifiedBinding, scope, insideTypeAnnotation,
+ ref.isInsideAnnotationAttribute, ref, ref.tokens, ref.sourcePositions);
+ }
+ /** Unified handling for true QualifiedNameReference and misclassified QualifiedTypeReference. */
+ private void internalCompletionOnQualifiedReference(ASTNode ref, ASTNode enclosingNode, Binding qualifiedBinding, Scope scope,
+ boolean insideTypeAnnotation, boolean isInsideAnnotationAttribute, InvocationSite site, char[][] tokens, long[] sourcePositions)
+ {
+ long completionPosition = sourcePositions[sourcePositions.length - 1];
if (qualifiedBinding.problemId() == ProblemReasons.NotFound) {
setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
// complete field members with missing fields type
@@ -3673,20 +3729,20 @@
(this.requestor.isAllowingRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_REF) ||
this.requestor.isAllowingRequiredProposals(CompletionProposal.METHOD_REF, CompletionProposal.TYPE_REF) ||
this.requestor.isAllowingRequiredProposals(CompletionProposal.TYPE_REF, CompletionProposal.TYPE_REF))) {
- if(ref.tokens.length == 1) {
- boolean foundSomeFields = findFieldsAndMethodsFromMissingFieldType(ref.tokens[0], scope, ref, insideTypeAnnotation);
+ if(tokens.length == 1) {
+ boolean foundSomeFields = findFieldsAndMethodsFromMissingFieldType(tokens[0], scope, site, insideTypeAnnotation);
if (!foundSomeFields) {
checkCancel();
findMembersFromMissingType(
- ref.tokens[0],
- ref.sourcePositions[0],
+ tokens[0],
+ sourcePositions[0],
null,
scope,
- ref,
- ref.isInsideAnnotationAttribute);
+ site,
+ isInsideAnnotationAttribute);
}
}
}
@@ -3703,7 +3759,7 @@
scope,
fieldsFound,
methodsFound,
- ref,
+ site,
scope,
false,
false,
@@ -3717,15 +3773,17 @@
checkCancel();
- findFieldsAndMethodsFromCastedReceiver(
+ if (ref instanceof Expression) {
+ findFieldsAndMethodsFromCastedReceiver(
enclosingNode,
qualifiedBinding,
scope,
fieldsFound,
methodsFound,
- ref,
+ site,
scope,
- ref);
+ (Expression) ref);
+ }
} else if (this.assistNodeInJavadoc == 0 &&
(this.requestor.isAllowingRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_REF) ||
@@ -3733,7 +3791,7 @@
boolean proposeField = !this.requestor.isIgnored(CompletionProposal.FIELD_REF);
boolean proposeMethod = !this.requestor.isIgnored(CompletionProposal.METHOD_REF);
if (proposeField || proposeMethod) {
- if(ref.tokens.length == 1) {
+ if(tokens.length == 1) {
if (qualifiedBinding instanceof LocalVariableBinding) {
// complete local variable members with missing variables type
// class X {
@@ -3746,7 +3804,7 @@
findFieldsAndMethodsFromMissingType(
localVariableBinding.declaration.type,
localVariableBinding.declaringScope,
- ref,
+ site,
scope);
} else {
// complete field members with missing fields type
@@ -3756,7 +3814,7 @@
// f.|
// }
// }
- findFieldsAndMethodsFromMissingFieldType(ref.tokens[0], scope, ref, insideTypeAnnotation);
+ findFieldsAndMethodsFromMissingFieldType(tokens[0], scope, site, insideTypeAnnotation);
}
}
@@ -3764,7 +3822,6 @@
}
} else if (qualifiedBinding instanceof ReferenceBinding && !(qualifiedBinding instanceof TypeVariableBinding)) {
- boolean isInsideAnnotationAttribute = ref.isInsideAnnotationAttribute;
ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding;
setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
@@ -3772,7 +3829,7 @@
this.completionToken,
receiverType,
scope,
- ref,
+ site,
isInsideAnnotationAttribute,
null,
null,
@@ -3781,7 +3838,7 @@
} else if (qualifiedBinding instanceof PackageBinding) {
- setSourceRange(astNode.sourceStart, (int) completionPosition);
+ setSourceRange(ref.sourceStart, (int) completionPosition);
setTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
// replace to the end of the completion identifier
@@ -3789,7 +3846,7 @@
}
}
- private void completionOnQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding,
+ private void completionOnQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, ASTNode enclosingNode, Binding qualifiedBinding,
Scope scope) {
this.insideQualifiedReference = true;
@@ -3807,6 +3864,8 @@
this.completionToken = ref.completionIdentifier;
long completionPosition = ref.sourcePositions[ref.tokens.length];
+ boolean haveTypeProposals = false;
+
// get the source positions of the completion identifier
if (qualifiedBinding.problemId() == ProblemReasons.NotFound) {
setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
@@ -3821,16 +3880,6 @@
}
} else if (qualifiedBinding instanceof ReferenceBinding && !(qualifiedBinding instanceof TypeVariableBinding)) {
ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding;
- if (astNodeParent instanceof LocalDeclaration && ref.nextToken == TerminalTokens.TokenNameLPAREN && !this.assistNodeIsConstructor) {
- // the subsequent '(' makes the interpretation as LocalDeclaration illegal (unless it's "new prefix.token()").
- // therefore we assume that "name(" (where name is LocalDeclaration.name) is the start of a new statement,
- // and propose *everything* that can be referenced via the receiverType:
- findMethods(this.completionToken, null, null, receiverType, scope, new ObjectVector(), true/*onlyStatic*/, false,
- FakeInvocationSite, scope, false, false, false, null, null, null, false, null, -1, -1);
- findFields(this.completionToken, receiverType, scope, new ObjectVector(), new ObjectVector(), true/*onlyStatic*/,
- FakeInvocationSite, scope, false, false, null, null, null, false, null, -1, -1);
- // fall through to propose member types
- }
if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
@@ -3859,6 +3908,7 @@
null,
null,
false);
+ haveTypeProposals = typesFound.size() > 0;
}
} else if (qualifiedBinding instanceof PackageBinding) {
@@ -3867,24 +3917,17 @@
// replace to the end of the completion identifier
findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding, scope);
}
- ASTNode parentNode = this.parser.assistNodeParent;
- if (ref.tokens.length > 0 && parentNode instanceof LocalDeclaration && ((LocalDeclaration) parentNode).type == ref) {
- // additionally check if 'prefix.' should be interpreted as a variable receiver rather then part of a type reference:
- Binding variable = scope.getBinding(ref.tokens[0], Binding.VARIABLE, FakeInvocationSite, true);
- lookupViaVariable: if (variable instanceof VariableBinding) {
- TypeBinding receiverType = ((VariableBinding) variable).type;
- int len = ref.tokens.length;
- for (int i=1; i<len; i++) {
- // lookup subsequent fields in 'prefix.q.r.'
- if (!(receiverType instanceof ReferenceBinding && receiverType.isValidBinding()))
- break lookupViaVariable;
- FieldBinding field = scope.getField(receiverType, ref.tokens[i], FakeInvocationSite);
- if (!field.isValidBinding())
- break lookupViaVariable;
- receiverType = field.type;
- }
- if (receiverType instanceof ReferenceBinding && receiverType.isValidBinding()) {
- findFieldsAndMethods(this.completionToken, receiverType, scope, new ObjectVector(), new ObjectVector(), FakeInvocationSite, scope, false, false, null, null, null, false, null, ref.sourceStart, (int)ref.sourcePositions[0]);
+ // alternatively interpret tokens in a misclassified LocalDeclaration like a QualifiedNameReference:
+ if (astNodeParent instanceof LocalDeclaration && enclosingNode != null) { // enclosingNode == null when called from completionOnProvidesInterfacesQualifiedTypeReference
+ if (scope instanceof BlockScope) {
+ // resolve tokens like it's done in CompletionOnQualifiedNameReference:
+ qualifiedBinding = ((BlockScope) scope).getBinding(ref.tokens, FakeInvocationSite);
+ boolean ignoreType = this.requestor.isIgnored(CompletionProposal.TYPE_REF);
+ try {
+ this.requestor.setIgnored(CompletionProposal.TYPE_REF, haveTypeProposals); // temp ignore types if already proposed above
+ internalCompletionOnQualifiedReference(ref, enclosingNode, qualifiedBinding, scope, false, false, FakeInvocationSite, ref.tokens, ref.sourcePositions);
+ } finally {
+ this.requestor.setIgnored(CompletionProposal.TYPE_REF, ignoreType);
}
}
}
@@ -3892,7 +3935,7 @@
private void completionOnProvidesInterfacesQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) {
// TODO: Filter the results wrt accessibility and add relevance to the results.
- completionOnQualifiedTypeReference(astNode, astNodeParent, qualifiedBinding, scope);
+ completionOnQualifiedTypeReference(astNode, astNodeParent, null, qualifiedBinding, scope);
}
private void completionOnProvidesImplementationsQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) {
@@ -6664,7 +6707,13 @@
relevance += computeRelevanceForResolution();
relevance += computeRelevanceForInterestingProposal(field);
relevance += computeRelevanceForCaseMatching(enumConstantName, field.name);
- relevance += computeRelevanceForExpectingType(field.type);
+ int computeRelevanceForExpectingType = computeRelevanceForExpectingType(field.type);
+ if(this.strictMatchForExtepectedType && computeRelevanceForExpectingType <= 0) {
+ continue;
+ } else if (!this.strictMatchForExtepectedType) {
+ relevance += computeRelevanceForExpectingType;
+ }
+
relevance += computeRelevanceForEnumConstant(field.type);
relevance += computeRelevanceForQualification(needQualification);
relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
@@ -7333,7 +7382,13 @@
relevance += computeRelevanceForResolution();
relevance += computeRelevanceForInterestingProposal(field);
relevance += computeRelevanceForCaseMatching(fieldName, field.name);
- relevance += computeRelevanceForExpectingType(field.type);
+ int computeRelevanceForExpectingType = computeRelevanceForExpectingType(field.type);
+ if(this.strictMatchForExtepectedType && computeRelevanceForExpectingType <= 0) {
+ continue;
+ } else if(!this.strictMatchForExtepectedType) {
+ relevance += computeRelevanceForExpectingType;
+ }
+
relevance += computeRelevanceForEnumConstant(field.type);
relevance += computeRelevanceForStatic(onlyStaticFields, field.isStatic());
relevance += computeRelevanceForFinal(this.assistNodeIsInsideCase, field.isFinal());
@@ -7543,7 +7598,7 @@
int nextPosition = 0;
do {
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
- if (notInJavadoc && itsInterfaces != Binding.NO_SUPERINTERFACES) {
+ if (notInJavadoc && itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
if (interfacesToVisit == null) {
interfacesToVisit = itsInterfaces;
nextPosition = interfacesToVisit.length;
@@ -8824,6 +8879,7 @@
findMembers,
getTypesMatchRule(),
IJavaSearchConstants.TYPE,
+ false,
this,
this.monitor);
acceptTypes(null);
@@ -9941,7 +9997,12 @@
relevance += computeRelevanceForResolution();
relevance += computeRelevanceForInterestingProposal();
relevance += computeRelevanceForCaseMatching(methodName, method.selector);
- relevance += computeRelevanceForExpectingType(method.returnType);
+ int computeRelevanceForExpectingType = computeRelevanceForExpectingType(method.returnType);
+ if(this.strictMatchForExtepectedType && computeRelevanceForExpectingType <= 0) {
+ continue;
+ } else if(!this.strictMatchForExtepectedType) {
+ relevance += computeRelevanceForExpectingType;
+ }
relevance += computeRelevanceForEnumConstant(method.returnType);
relevance += computeRelevanceForStatic(onlyStaticMethods, method.isStatic());
relevance += computeRelevanceForQualification(prefixRequired);
@@ -10224,7 +10285,13 @@
relevance += computeRelevanceForResolution();
relevance += computeRelevanceForInterestingProposal();
relevance += computeRelevanceForCaseMatching(methodName, method.selector);
- relevance += computeRelevanceForExpectingType(method.returnType);
+ int computeRelevanceForExpectingType = computeRelevanceForExpectingType(method.returnType);
+ if(this.strictMatchForExtepectedType && computeRelevanceForExpectingType <= 0) {
+ continue;
+ } else if(!this.strictMatchForExtepectedType) {
+ relevance += computeRelevanceForExpectingType;
+ }
+
relevance += computeRelevanceForEnumConstant(method.returnType);
relevance += computeRelevanceForStatic(true, method.isStatic());
relevance += computeRelevanceForQualification(true);
@@ -10464,8 +10531,20 @@
relevance += computeRelevanceForResolution();
relevance += computeRelevanceForInterestingProposal();
relevance += computeRelevanceForCaseMatching(methodName, method.selector);
- relevance += computeRelevanceForExpectingType(method.returnType);
- relevance += computeRelevanceForEnumConstant(method.returnType);
+ int computeRelevanceForExpectingType = computeRelevanceForExpectingType(method.returnType);
+ if(this.strictMatchForExtepectedType && computeRelevanceForExpectingType <= 0) {
+ continue;
+ } else if(!this.strictMatchForExtepectedType) {
+ relevance += computeRelevanceForExpectingType;
+ }
+
+ int computeRelevanceForEnumConstant = computeRelevanceForEnumConstant(method.returnType);
+ if(this.strictMatchForExtepectedType && computeRelevanceForEnumConstant <= 0) {
+ continue;
+ } else if(!this.strictMatchForExtepectedType) {
+ relevance += computeRelevanceForEnumConstant;
+ }
+
relevance += computeRelevanceForStatic(true, method.isStatic());
relevance += computeRelevanceForQualification(false);
relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
@@ -10573,7 +10652,9 @@
isInterface = receiverType.isInterface();
}
if (!isInterface) {
- findKeywords(token, new char[][] { Keywords.THIS, Keywords.SUPER }, true, false);
+ if (hasCompatibleEnclosing(scope, receiverType)) {
+ findKeywords(token, new char[][] { Keywords.THIS, Keywords.SUPER }, true, false);
+ }
} else {
boolean isEqual = false;
char[] enclosingSourceName = null;
@@ -10654,6 +10735,16 @@
}
}
+ private boolean hasCompatibleEnclosing(Scope scope, ReferenceBinding receiverType) {
+ ReferenceBinding enclosing = scope.enclosingSourceType();
+ while (enclosing != null) {
+ if (enclosing.isCompatibleWith(receiverType, scope))
+ return true;
+ enclosing = enclosing.enclosingType();
+ }
+ return false;
+ }
+
private void findMembersFromMissingType(
final char[] token,
final long pos,
@@ -12275,6 +12366,7 @@
this.nameEnvironment.findConstructorDeclarations(
token,
getTypesMatchRule(),
+ false,
this,
this.monitor);
acceptConstructors(scope);
@@ -12310,6 +12402,7 @@
proposeAllMemberTypes,
getTypesMatchRule(),
searchFor,
+ false,
this,
this.monitor);
acceptTypes(scope);
@@ -12478,6 +12571,7 @@
this.nameEnvironment.findConstructorDeclarations(
qualifiedName,
getTypesMatchRule(),
+ false,
this,
this.monitor);
acceptConstructors(scope);
@@ -12503,6 +12597,7 @@
false,
getTypesMatchRule(),
searchFor,
+ false,
this,
this.monitor);
acceptTypes(scope);
@@ -13467,6 +13562,17 @@
Scope invocationScope,
boolean insideTypeAnnotation,
boolean insideAnnotationAttribute) {
+ findVariablesAndMethods(token, scope, invocationSite, invocationScope, insideTypeAnnotation, insideAnnotationAttribute, true, new ObjectVector());
+ }
+ private void findVariablesAndMethods(
+ char[] token,
+ Scope scope,
+ InvocationSite invocationSite,
+ Scope invocationScope,
+ boolean insideTypeAnnotation,
+ boolean insideAnnotationAttribute,
+ boolean canBePrefixed,
+ ObjectVector methodsFound) {
if (token == null)
return;
@@ -13480,7 +13586,6 @@
ObjectVector localsFound = new ObjectVector();
ObjectVector fieldsFound = new ObjectVector();
- ObjectVector methodsFound = new ObjectVector();
Scope currentScope = scope;
@@ -13563,7 +13668,13 @@
relevance += computeRelevanceForResolution();
relevance += computeRelevanceForInterestingProposal(local);
relevance += computeRelevanceForCaseMatching(token, local.name);
- relevance += computeRelevanceForExpectingType(local.type);
+ int computeRelevanceForExpectingType = computeRelevanceForExpectingType(local.type);
+ if(this.strictMatchForExtepectedType && computeRelevanceForExpectingType <= 0) {
+ continue;
+ } else if(!this.strictMatchForExtepectedType) {
+ relevance += computeRelevanceForExpectingType;
+ }
+
relevance += computeRelevanceForEnumConstant(local.type);
relevance += computeRelevanceForQualification(false);
relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for local variable
@@ -13642,7 +13753,7 @@
invocationSite,
invocationScope,
true,
- true,
+ canBePrefixed,
null,
null,
null,
@@ -13665,7 +13776,7 @@
invocationScope,
true,
false,
- true,
+ canBePrefixed,
null,
null,
null,
@@ -13722,6 +13833,8 @@
token,
invocationScope,
fieldsFound);
+
+ findLambdaExpressions(currentScope);
}
}
@@ -14241,6 +14354,9 @@
case CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION :
buffer.append("ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION"); //$NON-NLS-1$
break;
+ case CompletionProposal.LAMBDA_EXPRESSION :
+ buffer.append("LAMBDA_EXPRESSION"); //$NON-NLS-1$
+ break;
default :
buffer.append("PROPOSAL"); //$NON-NLS-1$
break;
@@ -15439,4 +15555,66 @@
return completion;
}
// SH}
+
+ private void findLambdaExpressions(Scope scope) {
+ if (this.requestor.isIgnored(CompletionProposal.LAMBDA_EXPRESSION) ||
+ this.compilerOptions.sourceLevel < ClassFileConstants.JDK1_8) {
+ return;
+ }
+
+ if (this.expectedTypesPtr > -1) {
+ for (int i = 0; i <= this.expectedTypesPtr; i++) {
+ TypeBinding type = this.expectedTypes[i];
+
+ if (type.isFunctionalInterface(scope)) {
+ int relevance = computeBaseRelevance();
+ relevance += R_EXACT_EXPECTED_TYPE;
+ relevance += R_ABSTRACT_METHOD;
+ relevance += computeRelevanceForResolution();
+ relevance += computeRelevanceForInterestingProposal();
+ relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
+
+ // we are sure this is not null since we already check for eligibility
+ MethodBinding method = type.getSingleAbstractMethod(scope, true);
+ int length = method.parameters.length;
+ char[][] parameterTypeNames = new char[length][];
+
+ for (int j = 0; j < length; j++) {
+ TypeBinding p = method.parameters[j];
+ parameterTypeNames[j] = p.qualifiedSourceName();
+ }
+ char[][] parameterNames = findMethodParameterNames(method, parameterTypeNames);
+
+ InternalCompletionProposal proposal = createProposal(CompletionProposal.LAMBDA_EXPRESSION,
+ this.actualCompletionPosition);
+ proposal.setBinding(method);
+ proposal.setDeclarationSignature(getSignature(method.declaringClass));
+ proposal.setSignature(getSignature(method));
+ MethodBinding original = method.original();
+ if(original != method) {
+ proposal.setOriginalSignature(getSignature(original));
+ }
+ proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
+ proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
+ proposal.setRelevance(relevance);
+ proposal.setCompletion(LAMBDA);
+ proposal.setParameterTypeNames(parameterTypeNames);
+ proposal.setFlags(method.modifiers);
+ proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
+ proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
+ proposal.setName(method.selector);
+ proposal.setTypeName(method.returnType.qualifiedSourceName());
+ if (parameterNames != null) {
+ proposal.setParameterNames(parameterNames);
+ }
+
+ this.requestor.accept(proposal);
+ if (DEBUG) {
+ this.printDebug(proposal);
+ }
+ }
+ }
+ }
+ }
+
}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
index cc9befb..39cf53f 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
@@ -960,6 +960,7 @@
break;
case METHOD_REF:
case METHOD_REF_WITH_CASTED_RECEIVER:
+ case LAMBDA_EXPRESSION:
try {
this.parameterNames = findMethodParameterNames(
this.declarationPackageName,
@@ -1164,6 +1165,9 @@
case CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION :
buffer.append("ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION"); //$NON-NLS-1$
break;
+ case CompletionProposal.LAMBDA_EXPRESSION :
+ buffer.append("LAMBDA_EXPRESSION"); //$NON-NLS-1$
+ break;
default :
buffer.append("PROPOSAL"); //$NON-NLS-1$
break;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java
index 4ab064b..c69faaf 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java
@@ -40,7 +40,6 @@
public char[] completionIdentifier;
public boolean isConstructorType;
- public int nextToken;
public CompletionOnQualifiedTypeReference(char[][] previousIdentifiers, char[] completionIdentifier, long[] positions) {
this(previousIdentifiers, completionIdentifier, positions, K_TYPE);
@@ -50,10 +49,6 @@
this.completionIdentifier = completionIdentifier;
this.kind = kind;
}
-public CompletionOnQualifiedTypeReference(char[][] previousIdentifiers, char[] assistName, long[] positions, int kind, int nextToken) {
- this(previousIdentifiers, assistName, positions, kind);
- this.nextToken = nextToken;
-}
@Override
public void aboutToResolve(Scope scope) {
getTypeBinding(scope);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
index 138273f..a2480d0 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
@@ -21,6 +21,7 @@
package org.eclipse.jdt.internal.codeassist.complete;
import java.util.ArrayList;
+import java.util.Arrays;
/*
* Parser able to build specific completion parse nodes, given a cursorLocation.
@@ -4315,11 +4316,22 @@
if (token != TerminalTokens.TokenNameEOF && this.scanner.currentPosition > this.cursorLocation) {
if (!this.diet || this.dietInt != 0) { // do this also when parsing field initializers:
if (this.currentToken == TerminalTokens.TokenNameIdentifier
- && this.identifierStack[this.identifierPtr].length == 0
- && Scanner.isLiteral(token))
- {
- // <emptyAssistIdentifier> <someLiteral> is illegal and most likely the literal should be replaced => discard it now
- return fetchNextToken();
+ && this.identifierStack[this.identifierPtr].length == 0) {
+ if (Scanner.isLiteral(token)) {
+ // <emptyAssistIdentifier> <someLiteral> is illegal and most likely the literal should be replaced => discard it now
+ return fetchNextToken();
+ }
+ if (token == TerminalTokens.TokenNameIdentifier) {
+ // empty completion identifier followed by another identifier likely means the 2nd id should start another parse node.
+ // To cleanly separate them find a suitable separator:
+ this.scanner.currentPosition = this.scanner.startPosition; // return to startPosition after this charade
+ if (this.unstackedAct < ERROR_ACTION) {
+ if ("LocalVariableDeclaration".equals(reduce(TokenNameSEMICOLON))) //$NON-NLS-1$
+ return TokenNameSEMICOLON; // send ';' to terminate a local variable declaration
+ if ("ArgumentList".equals(reduce(TokenNameCOMMA))) //$NON-NLS-1$
+ return TokenNameCOMMA; // send ',' to terminate an argument in the list
+ }
+ }
}
}
if (!this.diet) { // only when parsing a method body:
@@ -4338,6 +4350,47 @@
}
return token;
}
+/*
+ * Variant of parse() without side effects that stops when another token would need to be fetched.
+ * Returns the name of the last reduced rule, or empty string if nothing reduced, or null if error was detected.
+ */
+String reduce(int token) {
+ int myStackTop = this.stateStackTop;
+ int[] myStack = Arrays.copyOf(this.stack, this.stack.length);
+ int act = this.unstackedAct;
+ String reduceName = ""; //$NON-NLS-1$
+ for (;;) {
+ int stackLength = myStack.length;
+ if (++myStackTop >= stackLength) {
+ System.arraycopy(
+ myStack, 0,
+ myStack = new int[stackLength + StackIncrement], 0,
+ stackLength);
+ }
+ myStack[myStackTop] = act;
+ act = tAction(act, token);
+ if (act == ERROR_ACTION)
+ return null;
+ if (act <= NUM_RULES) { // reduce
+ myStackTop--;
+ } else if (act > ERROR_ACTION) { // shift-reduce
+ return reduceName; // ready to accept the next token
+ } else {
+ if (act < ACCEPT_ACTION) { // shift
+ return reduceName; // ready to accept the next token
+ }
+ return reduceName; // ?
+ }
+ do {
+ reduceName = name[non_terminal_index[lhs[act]]];
+ myStackTop -= (rhs[act] - 1);
+ act = ntAction(myStack[myStackTop], lhs[act]);
+ if (act == ACCEPT_ACTION) {
+ return reduceName;
+ }
+ } while (act <= NUM_RULES);
+ }
+}
@Override
protected void consumeToken(int token) {
if(this.isFirst) {
@@ -5410,7 +5463,7 @@
if (ref != null)
return ref;
return new CompletionOnQualifiedTypeReference(previousIdentifiers, assistName, positions,
- CompletionOnQualifiedTypeReference.K_TYPE, this.currentToken);
+ CompletionOnQualifiedTypeReference.K_TYPE);
}
}
@Override
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index 4e56c56..3263a86 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -2844,6 +2844,8 @@
int LocalStaticsIllegalVisibilityModifierForInterfaceLocalType = TypeRelated + 1765;
/** @since 3.28 */
int IllegalModifierForLocalEnumDeclaration = TypeRelated + 1766;
+ /** @since 3.28 */
+ int ClassExtendFinalRecord = TypeRelated + 1767;
/* records - end */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
index e3c3116..d3eb821 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
@@ -73,10 +73,13 @@
FlowContext flowContext,
FlowInfo flowInfo) {
if (this.constantExpressions != null) {
+ int nullPatternCount = 0;
for(int i=0; i < this.constantExpressions.length; i++) {
Expression e = this.constantExpressions[i];
+ nullPatternCount += e instanceof NullLiteral ? 1 : 0;
if (i > 0 && (e instanceof Pattern)) {
- currentScope.problemReporter().IllegalFallThroughToPattern(e);
+ if (!(i == nullPatternCount && e instanceof TypePattern))
+ currentScope.problemReporter().IllegalFallThroughToPattern(e);
}
analyseConstantExpression(currentScope, flowContext, flowInfo, e);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
index 727128f..2124bb5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
@@ -974,7 +974,7 @@
this.constructorCall = null;
} else if (sourceType.isRecord() &&
!(this instanceof CompactConstructorDeclaration) && // compact constr should be marked as canonical?
- (this.binding != null && (this.binding.tagBits & TagBits.IsCanonicalConstructor) == 0) &&
+ (this.binding != null && !this.binding.isCanonicalConstructor()) &&
this.constructorCall.accessMode != ExplicitConstructorCall.This) {
this.scope.problemReporter().recordMissingExplicitConstructorCallInNonCanonicalConstructor(this);
this.constructorCall = null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
index 7b7ab4a..9ed8878 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
@@ -396,7 +396,7 @@
try {
AbstractMethodDeclaration methodDeclaration = methodScope.referenceMethod();
if (methodDeclaration != null && methodDeclaration.binding != null
- && (methodDeclaration.binding.tagBits & TagBits.IsCanonicalConstructor) != 0) {
+ && methodDeclaration.binding.isCanonicalConstructor()) {
if (!checkAndFlagExplicitConstructorCallInCanonicalConstructor(methodDeclaration, scope))
return;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index fbe62b7..645515b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -700,7 +700,7 @@
hasAbstractMethods = hasAbstractMethods || methodBinding.isAbstract();
hasNativeMethods = hasNativeMethods || methodBinding.isNative();
if (methods[i].isCanonicalConstructor()) {
- methodBinding.tagBits |= TagBits.IsCanonicalConstructor;
+ methodBinding.extendedTagBits |= ExtendedTagBits.IsCanonicalConstructor;
}
}
}
@@ -1848,7 +1848,11 @@
if (!superclass.isClass() && (superclass.tagBits & TagBits.HasMissingType) == 0) {
problemReporter().superclassMustBeAClass(sourceType, superclassRef, superclass);
} else if (superclass.isFinal()) {
- problemReporter().classExtendFinalClass(sourceType, superclassRef, superclass);
+ if (superclass.isRecord()) {
+ problemReporter().classExtendFinalRecord(sourceType, superclassRef, superclass);
+ } else {
+ problemReporter().classExtendFinalClass(sourceType, superclassRef, superclass);
+ }
} else if ((superclass.tagBits & TagBits.HasDirectWildcard) != 0) {
problemReporter().superTypeCannotUseWildcard(sourceType, superclassRef, superclass);
} else if (superclass.erasure().id == TypeIds.T_JavaLangEnum) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtendedTagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtendedTagBits.java
index 0e96a53..6d87856 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtendedTagBits.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtendedTagBits.java
@@ -24,4 +24,9 @@
* Flag used to identify the annotation jdk.internal.ValueBased
*/
int AnnotationValueBased = ASTNode.Bit3;
+
+ // Java 16 Records
+ int IsCanonicalConstructor = ASTNode.Bit4; // constructor
+ int isImplicit = ASTNode.Bit5; // constructor and method
+
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
index ee2898a..415b9bf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
@@ -124,6 +124,7 @@
public TypeVariableBinding[] typeVariables = Binding.NO_TYPE_VARIABLES;
char[] signature;
public long tagBits;
+ public int extendedTagBits = 0; // See values in the interface ExtendedTagBits
// Used only for constructors
protected AnnotationBinding [] typeAnnotations = Binding.NO_ANNOTATIONS;
@@ -1256,6 +1257,12 @@
return this.selector == TypeConstants.INIT;
}
+/* Answer true if the method is a canonical constructor
+*/
+public final boolean isCanonicalConstructor() {
+ return (this.extendedTagBits & ExtendedTagBits.IsCanonicalConstructor) != 0;
+}
+
/* Answer true if the receiver is a compact constructor
*/
public final boolean isCompactConstructor() {
@@ -1300,6 +1307,14 @@
return (this.modifiers & ExtraCompilerModifiers.AccImplementing) != 0;
}
+
+/* Answer true if the method is an implicit method - only for records
+*/
+public final boolean isImplicit() {
+ return (this.extendedTagBits & ExtendedTagBits.isImplicit) != 0;
+}
+
+
/*
* Answer true if the receiver is a "public static void main(String[])" method
*/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
index d6245f5..585a287 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
@@ -543,8 +543,9 @@
}
private void checkAndSetRecordCanonicalConsAndMethods(AbstractMethodDeclaration am) {
if (am.binding != null && (am.bits & ASTNode.IsImplicit) != 0) {
- am.binding.tagBits |= TagBits.isImplicit;
- am.binding.tagBits |= (am.bits & ASTNode.IsCanonicalConstructor) != 0 ? TagBits.IsCanonicalConstructor : 0;
+ am.binding.extendedTagBits |= ExtendedTagBits.isImplicit;
+ if ((am.bits & ASTNode.IsCanonicalConstructor) != 0)
+ am.binding.extendedTagBits |= ExtendedTagBits.IsCanonicalConstructor;
}
}
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 b84adc6..dc347d6 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
@@ -1795,7 +1795,7 @@
if (method != null && method.isValidBinding() && method.isVarargs()) {
TypeBinding elementType = method.parameters[method.parameters.length - 1].leafComponentType();
if (elementType instanceof ReferenceBinding) {
- if (!((ReferenceBinding) elementType).canBeSeenBy(this)) {
+ if (!((ReferenceBinding) elementType).erasure().canBeSeenBy(this)) {
return new ProblemMethodBinding(method, method.selector, invocationSite.genericTypeArguments(), ProblemReasons.VarargsElementTypeNotVisible);
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 25a4ad1..bd46612 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -1184,8 +1184,7 @@
if (this.isRecordDeclaration && getImplicitCanonicalConstructor() == -1) {
MethodBinding explicitCanon = null;
for (MethodBinding m : methodBindings) {
- if (m.isCompactConstructor()
- || (m.tagBits & TagBits.IsCanonicalConstructor) != 0) {
+ if (m.isCompactConstructor() || m.isCanonicalConstructor()) {
explicitCanon = m;
break;
}
@@ -2756,7 +2755,7 @@
if (this.methods != null && this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) {
for (int i = 0, l = this.methods.length; i < l; ++i) {
MethodBinding method = this.methods[i];
- if ((method.tagBits & TagBits.IsCanonicalConstructor ) != 0 && (method.tagBits & TagBits.isImplicit) != 0)
+ if (method.isCanonicalConstructor() && method.isImplicit())
return i;
}
}
@@ -2769,7 +2768,7 @@
for (MethodBinding method : this.methods) {
if (!method.isConstructor())
continue;
- if ((method.tagBits & TagBits.isImplicit) != 0) {
+ if (method.isImplicit()) {
continue;
}
if (method.parameters.length != nRecordComponents)
@@ -2798,7 +2797,7 @@
MethodBinding method = resolvedMethods[i];
if (method == null || !CharOperation.equals(method.selector, name))
continue;
- if ((method.tagBits & TagBits.isImplicit) != 0 || method instanceof SyntheticMethodBinding)
+ if (method.isImplicit() || method instanceof SyntheticMethodBinding)
return i;
}
}
@@ -3141,7 +3140,7 @@
if (explicitCanonicalConstructor.thrownExceptions != null && explicitCanonicalConstructor.thrownExceptions.length > 0)
this.scope.problemReporter().recordCanonicalConstructorHasThrowsClause(methodDecl);
checkCanonicalConstructorParameterNames(explicitCanonicalConstructor, methodDecl);
- explicitCanonicalConstructor.tagBits |= TagBits.IsCanonicalConstructor;
+ explicitCanonicalConstructor.extendedTagBits |= ExtendedTagBits.IsCanonicalConstructor;
// checkAndFlagExplicitConstructorCallInCanonicalConstructor(methodDecl);
return explicitCanonicalConstructor;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
index ec33a91..6099069 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
@@ -552,7 +552,8 @@
if (this.declaringClass.isStrictfp())
this.modifiers |= ClassFileConstants.AccStrictfp;
this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
- this.tagBits |= (TagBits.IsCanonicalConstructor | TagBits.isImplicit);
+ this.extendedTagBits |= ExtendedTagBits.IsCanonicalConstructor;
+ this.extendedTagBits |= ExtendedTagBits.isImplicit;
this.parameters = rcb.length == 0 ? Binding.NO_PARAMETERS : new TypeBinding[rcb.length];
for (int i = 0; i < rcb.length; i++) this.parameters[i] = TypeBinding.VOID; // placeholder
this.selector = TypeConstants.INIT;
@@ -560,7 +561,6 @@
this.purpose = SyntheticMethodBinding.RecordCanonicalConstructor;
this.thrownExceptions = Binding.NO_EXCEPTIONS;
this.declaringClass = declaringSourceType;
- this.tagBits |= TagBits.IsCanonicalConstructor;
this.index = nextSmbIndex();
}
public SyntheticMethodBinding(ReferenceBinding declaringClass, RecordComponentBinding rcb, int index) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
index 283739d..d830603 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
@@ -70,10 +70,6 @@
long MultiCatchParameter = ASTNode.Bit13; // local
long IsResource = ASTNode.Bit14; // local
- // for java 14 Records Canonical constructor (preview)
- long IsCanonicalConstructor = ASTNode.Bit12; // constructor
- long isImplicit = ASTNode.Bit13; // constructor and method
-
// have implicit null annotations been collected (inherited(?) & default)?
long IsNullnessKnown = ASTNode.Bit13; // method
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
index 866b004..9bda423 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
@@ -33,6 +33,7 @@
import org.eclipse.jdt.internal.compiler.impl.JavaFeature;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+import org.eclipse.jdt.internal.compiler.util.CharDeduplication;
import org.eclipse.jdt.internal.compiler.util.Util;
/**
@@ -337,41 +338,6 @@
public static final String INVALID_UNDERSCORE = "Invalid_Underscore"; //$NON-NLS-1$
public static final String UNDERSCORES_IN_LITERALS_NOT_BELOW_17 = "Underscores_In_Literals_Not_Below_17"; //$NON-NLS-1$
- //----------------optimized identifier managment------------------
- static final char[] charArray_a = new char[] {'a'},
- charArray_b = new char[] {'b'},
- charArray_c = new char[] {'c'},
- charArray_d = new char[] {'d'},
- charArray_e = new char[] {'e'},
- charArray_f = new char[] {'f'},
- charArray_g = new char[] {'g'},
- charArray_h = new char[] {'h'},
- charArray_i = new char[] {'i'},
- charArray_j = new char[] {'j'},
- charArray_k = new char[] {'k'},
- charArray_l = new char[] {'l'},
- charArray_m = new char[] {'m'},
- charArray_n = new char[] {'n'},
- charArray_o = new char[] {'o'},
- charArray_p = new char[] {'p'},
- charArray_q = new char[] {'q'},
- charArray_r = new char[] {'r'},
- charArray_s = new char[] {'s'},
- charArray_t = new char[] {'t'},
- charArray_u = new char[] {'u'},
- charArray_v = new char[] {'v'},
- charArray_w = new char[] {'w'},
- charArray_x = new char[] {'x'},
- charArray_y = new char[] {'y'},
- charArray_z = new char[] {'z'};
-
- static final char[] initCharArray =
- new char[] {'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000'};
- static final int TableSize = 30, InternalTableSize = 6; //30*6 =210 entries
-
- public static final int OptimizedLength = 6;
- public /*static*/ final char[][][][] charArray_length =
- new char[OptimizedLength - 1][TableSize][InternalTableSize][];
// support for detecting non-externalized string literals
public static final char[] TAG_PREFIX= "//$NON-NLS-".toCharArray(); //$NON-NLS-1$
public static final int TAG_PREFIX_LENGTH= TAG_PREFIX.length;
@@ -392,20 +358,6 @@
// generic support
public boolean returnOnlyGreater = false;
- /*static*/ {
- for (int i = 0; i < OptimizedLength - 1; i++) {
- for (int j = 0; j < TableSize; j++) {
- for (int k = 0; k < InternalTableSize; k++) {
- this.charArray_length[i][j][k] = initCharArray;
- }
- }
- }
- }
- /*static*/ int newEntry2 = 0,
- newEntry3 = 0,
- newEntry4 = 0,
- newEntry5 = 0,
- newEntry6 = 0;
public boolean insideRecovery = false;
int lookBack[] = new int[2]; // fall back to spring forward.
protected int nextToken = TokenNameNotAToken; // allows for one token push back, only the most recent token can be reliably ungotten.
@@ -432,6 +384,8 @@
//Java 15 - first _ keyword appears
Map<String, Integer> _Keywords = null;
+ private CharDeduplication deduplication = CharDeduplication.getThreadLocalInstance();
+
public Scanner() {
this(false /*comment*/, false /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3 /*sourceLevel*/, null/*taskTag*/, null/*taskPriorities*/, true /*taskCaseSensitive*/);
}
@@ -696,24 +650,9 @@
}
int length = this.currentPosition - this.startPosition;
if (length == this.eofPosition) return this.source;
- switch (length) { // see OptimizedLength
- case 1 :
- return optimizedCurrentTokenSource1();
- case 2 :
- return optimizedCurrentTokenSource2();
- case 3 :
- return optimizedCurrentTokenSource3();
- case 4 :
- return optimizedCurrentTokenSource4();
- case 5 :
- return optimizedCurrentTokenSource5();
- case 6 :
- return optimizedCurrentTokenSource6();
- }
- char[] result = new char[length];
- System.arraycopy(this.source, this.startPosition, result, 0, length);
- return result;
+ return this.deduplication.sharedCopyOfRange(this.source, this.startPosition, this.currentPosition);
}
+
public int getCurrentTokenEndPosition(){
return this.currentPosition - 1;
}
@@ -958,6 +897,9 @@
case 's' :
result.append(' ');
break;
+ case '"':
+ result.append('"');
+ break;
case 'b' :
result.append('\b');
break;
@@ -2446,12 +2388,17 @@
case 'n' :
case 'r' :
case 'f' :
+ case 's' :
break outer;
case '\n' :
case '\r' :
this.currentCharacter = '\\';
this.currentPosition++;
break;
+ case '\"' :
+ this.currentPosition++;
+ this.currentCharacter = this.source[this.currentPosition++];
+ continue;
case '\\' :
this.currentPosition++;
break;
@@ -2709,7 +2656,7 @@
pushLineSeparator();
//$FALL-THROUGH$
default:
- if (this.currentCharacter == '\\' && this.source[this.currentPosition++] == '"') {
+ if (this.currentCharacter == '\\' && this.source[this.currentPosition] == '"') {
this.currentPosition++;
}
this.currentCharacter = this.source[this.currentPosition++];
@@ -3391,241 +3338,6 @@
return CharOperation.isWhitespace(this.currentCharacter);
}
-final char[] optimizedCurrentTokenSource1() {
- //return always the same char[] build only once
-
- //optimization at no speed cost of 99.5 % of the singleCharIdentifier
- char charOne = this.source[this.startPosition];
- switch (charOne) {
- case 'a' :
- return charArray_a;
- case 'b' :
- return charArray_b;
- case 'c' :
- return charArray_c;
- case 'd' :
- return charArray_d;
- case 'e' :
- return charArray_e;
- case 'f' :
- return charArray_f;
- case 'g' :
- return charArray_g;
- case 'h' :
- return charArray_h;
- case 'i' :
- return charArray_i;
- case 'j' :
- return charArray_j;
- case 'k' :
- return charArray_k;
- case 'l' :
- return charArray_l;
- case 'm' :
- return charArray_m;
- case 'n' :
- return charArray_n;
- case 'o' :
- return charArray_o;
- case 'p' :
- return charArray_p;
- case 'q' :
- return charArray_q;
- case 'r' :
- return charArray_r;
- case 's' :
- return charArray_s;
- case 't' :
- return charArray_t;
- case 'u' :
- return charArray_u;
- case 'v' :
- return charArray_v;
- case 'w' :
- return charArray_w;
- case 'x' :
- return charArray_x;
- case 'y' :
- return charArray_y;
- case 'z' :
- return charArray_z;
- default :
- return new char[] {charOne};
- }
-}
-final char[] optimizedCurrentTokenSource2() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0 , c1;
- int hash = (((c0=src[start]) << 6) + (c1=src[start+1])) % TableSize;
- char[][] table = this.charArray_length[0][hash];
- int i = this.newEntry2;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0]) && (c1 == charArray[1]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry2;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0]) && (c1 == charArray[1]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[2], 0, 2);
- //newIdentCount++;
- return table[this.newEntry2 = max] = r; //(r = new char[] {c0, c1});
-}
-final char[] optimizedCurrentTokenSource3() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0, c1=src[start+1], c2;
- int hash = (((c0=src[start])<< 6) + (c2=src[start+2])) % TableSize;
-// int hash = ((c0 << 12) + (c1<< 6) + c2) % TableSize;
- char[][] table = this.charArray_length[1][hash];
- int i = this.newEntry3;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry3;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[3], 0, 3);
- //newIdentCount++;
- return table[this.newEntry3 = max] = r; //(r = new char[] {c0, c1, c2});
-}
-final char[] optimizedCurrentTokenSource4() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0, c1 = src[start+1], c2, c3 = src[start+3];
- int hash = (((c0=src[start]) << 6) + (c2=src[start+2])) % TableSize;
-// int hash = (int) (((((long) c0) << 18) + (c1 << 12) + (c2 << 6) + c3) % TableSize);
- char[][] table = this.charArray_length[2][hash];
- int i = this.newEntry4;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry4;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[4], 0, 4);
- //newIdentCount++;
- return table[this.newEntry4 = max] = r; //(r = new char[] {c0, c1, c2, c3});
-}
-final char[] optimizedCurrentTokenSource5() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0, c1 = src[start+1], c2, c3 = src[start+3], c4;
- int hash = (((c0=src[start]) << 12) +((c2=src[start+2]) << 6) + (c4=src[start+4])) % TableSize;
-// int hash = (int) (((((long) c0) << 24) + (((long) c1) << 18) + (c2 << 12) + (c3 << 6) + c4) % TableSize);
- char[][] table = this.charArray_length[3][hash];
- int i = this.newEntry5;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3])
- && (c4 == charArray[4]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry5;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3])
- && (c4 == charArray[4]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[5], 0, 5);
- //newIdentCount++;
- return table[this.newEntry5 = max] = r; //(r = new char[] {c0, c1, c2, c3, c4});
-}
-final char[] optimizedCurrentTokenSource6() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0, c1 = src[start+1], c2, c3 = src[start+3], c4, c5 = src[start+5];
- int hash = (((c0=src[start]) << 12) +((c2=src[start+2]) << 6) + (c4=src[start+4])) % TableSize;
-// int hash = (int)(((((long) c0) << 32) + (((long) c1) << 24) + (((long) c2) << 18) + (c3 << 12) + (c4 << 6) + c5) % TableSize);
- char[][] table = this.charArray_length[4][hash];
- int i = this.newEntry6;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3])
- && (c4 == charArray[4])
- && (c5 == charArray[5]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry6;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3])
- && (c4 == charArray[4])
- && (c5 == charArray[5]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[6], 0, 6);
- //newIdentCount++;
- return table[this.newEntry6 = max] = r; //(r = new char[] {c0, c1, c2, c3, c4, c5});
-}
public boolean isInModuleDeclaration() {
return this.fakeInModule || this.insideModuleInfo ||
(this.activeParser != null ? this.activeParser.isParsingModuleDeclaration() : false);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index 5b55bf9..4dae25d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -1846,6 +1846,18 @@
superclass.sourceStart,
superclass.sourceEnd);
}
+public void classExtendFinalRecord(SourceTypeBinding type, TypeReference superclass, TypeBinding superTypeBinding) {
+ String name = new String(type.sourceName());
+ String superTypeFullName = new String(superTypeBinding.readableName());
+ String superTypeShortName = new String(superTypeBinding.shortReadableName());
+ if (superTypeShortName.equals(name)) superTypeShortName = superTypeFullName;
+ this.handle(
+ IProblem.ClassExtendFinalRecord,
+ new String[] {superTypeFullName, name},
+ new String[] {superTypeShortName, name},
+ superclass.sourceStart,
+ superclass.sourceEnd);
+}
public void codeSnippetMissingClass(String missing, int start, int end) {
String[] arguments = new String[]{missing};
this.handle(
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index 74d3628..55daf07 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -1071,6 +1071,7 @@
1765 = Illegal modifier for the local interface {0}; abstract and strictfp are the only modifiers allowed explicitly
1766 = Illegal modifier for local enum {0}; no explicit modifier is permitted
+1767 = The record {0} cannot be the superclass of {1}; a record is final and cannot be extended
1780 = The pattern variable {0} is not in scope in this location
1781 = The pattern variable {0} is final and cannot be assigned again
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/CharDeduplication.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/CharDeduplication.java
new file mode 100644
index 0000000..50dc2fa
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/CharDeduplication.java
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ * Copyright (c) 2021 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Joerg Kubitz - threadlocal refactoring, all ASCII chars
+ * - (copied content from PublicScanner.java / Scanner.java)
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.util;
+
+import java.lang.ref.SoftReference;
+import java.util.Arrays;
+import java.util.function.Supplier;
+
+public class CharDeduplication {
+
+ // ----- immutable static part (thread safe): ----
+
+ static final char[] ASCII_CHARS[] = new char[128][];
+ static {
+ for (int i = 0; i < ASCII_CHARS.length; i++) {
+ ASCII_CHARS[i] = new char[] { (char) i };
+ }
+ }
+ public static final int TABLE_SIZE = 30; // XXX thats not a prime -> bad for hashing, nor a power of 2 -> expensive
+ // modulo computation
+ public static final int INTERNAL_TABLE_SIZE = 6; // 30*6 =180 entries
+
+ public static final int OPTIMIZED_LENGTH = 6;
+
+ private final static char[] CHAR_ARRAY0 = new char[0];
+
+ /** avoid OOME by additional CharDeduplication memory **/
+ static final class CacheReference<T> {
+ private SoftReference<T> reference;
+ private final Supplier<? extends T> supplier;
+
+ CacheReference(Supplier<? extends T> supplier) {
+ this.supplier = supplier;
+ this.reference = new SoftReference<>(supplier.get());
+ }
+
+ T get() {
+ T referent = this.reference.get();
+ if (referent == null) {
+ referent = this.supplier.get();
+ this.reference = new SoftReference<>(referent);
+ }
+ return referent;
+ }
+ }
+
+ private final static ThreadLocal<CacheReference<CharDeduplication>> mutableCache = ThreadLocal.withInitial(()->new CacheReference<>(CharDeduplication::new));
+
+ private static final char[] optimizedCurrentTokenSource1(char[] source, int startPosition) {
+ // optimization at no speed cost of 99.5 % of the singleCharIdentifier
+ char charOne = source[startPosition];
+ if (charOne < ASCII_CHARS.length) {
+ return ASCII_CHARS[charOne];
+ }
+ return new char[] { charOne };
+ }
+
+ /** @return an instance that is *not* thread safe. To be used in a single thread only. **/
+ public static CharDeduplication getThreadLocalInstance() {
+ return mutableCache.get().get();
+ }
+
+ // ----- mutable non-static part (not thread safe!): ----
+
+ /** single threaded only **/
+ public final char[][][][] charArray_length = new char[OPTIMIZED_LENGTH - 1][TABLE_SIZE][INTERNAL_TABLE_SIZE][];
+
+ int newEntry2 = 0;
+ int newEntry3 = 0;
+ int newEntry4 = 0;
+ int newEntry5 = 0;
+ int newEntry6 = 0;
+
+ private CharDeduplication() {
+ init();
+ }
+
+ private void init() {
+ for (int i = 0; i < OPTIMIZED_LENGTH - 1; i++) {
+ final char[] initCharArray = new char[i + 2];
+ for (int j = 0; j < TABLE_SIZE; j++) {
+ for (int k = 0; k < INTERNAL_TABLE_SIZE; k++) {
+ this.charArray_length[i][j][k] = initCharArray;
+ }
+ }
+ }
+ }
+
+ /** public for test purpose only **/
+ @Deprecated
+ public void reset() {
+ init();
+ }
+
+ /**
+ * like Arrays.copyOfRange(source, from, to) but returns a cached instance of the former result if
+ * available
+ *
+ * @param from
+ * start index (inclusive)
+ * @param to
+ * end index (exclusive)
+ * @return source[from..to-1]
+ * @see java.util.Arrays#copyOfRange(char[], int, int)
+ **/
+ public char[] sharedCopyOfRange(char[] source, int from, int to) {
+ int length = to - from;
+ switch (length) { // see OptimizedLength
+ case 1:
+ return optimizedCurrentTokenSource1(source, from);
+ case 2:
+ return optimizedCurrentTokenSource2(source, from);
+ case 3:
+ return optimizedCurrentTokenSource3(source, from);
+ case 4:
+ return optimizedCurrentTokenSource4(source, from);
+ case 5:
+ return optimizedCurrentTokenSource5(source, from);
+ case 6:
+ return optimizedCurrentTokenSource6(source, from);
+ case 0:
+ return CHAR_ARRAY0;
+ }
+ return Arrays.copyOfRange(source, from, to);
+ }
+
+ private final char[] optimizedCurrentTokenSource2(char[] source, int startPosition) {
+
+ char[] src = source;
+ int start = startPosition;
+ char c0, c1;
+ int hash = (((c0 = src[start]) << 6) + (c1 = src[start + 1])) % TABLE_SIZE;
+ char[][] table = this.charArray_length[0][hash];
+ int i = this.newEntry2;
+ while (++i < INTERNAL_TABLE_SIZE) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]))
+ return charArray;
+ }
+ // ---------other side---------
+ i = -1;
+ int max = this.newEntry2;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]))
+ return charArray;
+ }
+ // --------add the entry-------
+ if (++max >= INTERNAL_TABLE_SIZE)
+ max = 0;
+ char[] r;
+ System.arraycopy(src, start, r = new char[2], 0, 2);
+ return table[this.newEntry2 = max] = r;
+ }
+
+ private final char[] optimizedCurrentTokenSource3(char[] source, int startPosition) {
+ char[] src = source;
+ int start = startPosition;
+ char c0, c1 = src[start + 1], c2;
+ int hash = (((c0 = src[start]) << 6) + (c2 = src[start + 2])) % TABLE_SIZE;
+ char[][] table = this.charArray_length[1][hash];
+ int i = this.newEntry3;
+ while (++i < INTERNAL_TABLE_SIZE) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
+ return charArray;
+ }
+ // ---------other side---------
+ i = -1;
+ int max = this.newEntry3;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
+ return charArray;
+ }
+ // --------add the entry-------
+ if (++max >= INTERNAL_TABLE_SIZE)
+ max = 0;
+ char[] r;
+ System.arraycopy(src, start, r = new char[3], 0, 3);
+ return table[this.newEntry3 = max] = r;
+ }
+
+ private final char[] optimizedCurrentTokenSource4(char[] source, int startPosition) {
+ char[] src = source;
+ int start = startPosition;
+ char c0, c1 = src[start + 1], c2, c3 = src[start + 3];
+ int hash = (((c0 = src[start]) << 6) + (c2 = src[start + 2])) % TABLE_SIZE;
+ char[][] table = this.charArray_length[2][hash];
+ int i = this.newEntry4;
+ while (++i < INTERNAL_TABLE_SIZE) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3]))
+ return charArray;
+ }
+ // ---------other side---------
+ i = -1;
+ int max = this.newEntry4;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3]))
+ return charArray;
+ }
+ // --------add the entry-------
+ if (++max >= INTERNAL_TABLE_SIZE)
+ max = 0;
+ char[] r;
+ System.arraycopy(src, start, r = new char[4], 0, 4);
+ return table[this.newEntry4 = max] = r;
+ }
+
+ private final char[] optimizedCurrentTokenSource5(char[] source, int startPosition) {
+ char[] src = source;
+ int start = startPosition;
+ char c0, c1 = src[start + 1], c2, c3 = src[start + 3], c4;
+ int hash = (((c0 = src[start]) << 12) + ((c2 = src[start + 2]) << 6) + (c4 = src[start + 4])) % TABLE_SIZE;
+ char[][] table = this.charArray_length[3][hash];
+ int i = this.newEntry5;
+ while (++i < INTERNAL_TABLE_SIZE) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])
+ && (c4 == charArray[4]))
+ return charArray;
+ }
+ // ---------other side---------
+ i = -1;
+ int max = this.newEntry5;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])
+ && (c4 == charArray[4]))
+ return charArray;
+ }
+ // --------add the entry-------
+ if (++max >= INTERNAL_TABLE_SIZE)
+ max = 0;
+ char[] r;
+ System.arraycopy(src, start, r = new char[5], 0, 5);
+ return table[this.newEntry5 = max] = r;
+ }
+
+ private final char[] optimizedCurrentTokenSource6(char[] source, int startPosition) {
+ char[] src = source;
+ int start = startPosition;
+ char c0, c1 = src[start + 1], c2, c3 = src[start + 3], c4, c5 = src[start + 5];
+ int hash = (((c0 = src[start]) << 12) + ((c2 = src[start + 2]) << 6) + (c4 = src[start + 4])) % TABLE_SIZE;
+ char[][] table = this.charArray_length[4][hash];
+ int i = this.newEntry6;
+ while (++i < INTERNAL_TABLE_SIZE) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])
+ && (c4 == charArray[4]) && (c5 == charArray[5]))
+ return charArray;
+ }
+ // ---------other side---------
+ i = -1;
+ int max = this.newEntry6;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])
+ && (c4 == charArray[4]) && (c5 == charArray[5]))
+ return charArray;
+ }
+ // --------add the entry-------
+ if (++max >= INTERNAL_TABLE_SIZE)
+ max = 0;
+ char[] r;
+ System.arraycopy(src, start, r = new char[6], 0, 6);
+ return table[this.newEntry6 = max] = r;
+ }
+}
diff --git a/org.eclipse.jdt.core/docker/build-ubuntu-jikespg.sh b/org.eclipse.jdt.core/docker/build-ubuntu-jikespg.sh
new file mode 100644
index 0000000..5bf436d
--- /dev/null
+++ b/org.eclipse.jdt.core/docker/build-ubuntu-jikespg.sh
@@ -0,0 +1,21 @@
+#!/bin/bash -x
+#*******************************************************************************
+# Copyright (c) 2021 IBM Corporation and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# Sravan Kumar Lakkimsetti - initial API and implementation
+#*******************************************************************************
+
+set -e
+
+pushd jikespg
+echo "Building Ubuntu based Jikes Parser Generator Ubuntu docker image"
+docker build --pull -t eclipse/platformreleng-ubuntu-gtk3-metacity:jikespg .
+popd
diff --git a/org.eclipse.jdt.core/docker/jikespg/Dockerfile b/org.eclipse.jdt.core/docker/jikespg/Dockerfile
new file mode 100644
index 0000000..63e507b
--- /dev/null
+++ b/org.eclipse.jdt.core/docker/jikespg/Dockerfile
@@ -0,0 +1,31 @@
+FROM ubuntu:20.04
+
+### user name recognition at runtime w/ an arbitrary uid - for OpenShift deployments
+COPY scripts/uid_entrypoint /usr/local/bin/uid_entrypoint
+RUN chmod u+x /usr/local/bin/uid_entrypoint && \
+ chgrp 0 /usr/local/bin/uid_entrypoint && \
+ chmod g=u /usr/local/bin/uid_entrypoint /etc/passwd
+ENTRYPOINT [ "uid_entrypoint" ]
+
+ENV DEBIAN_FRONTEND noninteractive
+RUN apt-get update && apt upgrade -y && apt dist-upgrade -y && apt-get install -y --no-install-recommends \
+ wget \
+ curl \
+ unzip \
+ vim \
+ gcc \
+ g++ \
+ make \
+ git \
+ && rm -rf /var/lib/apt/lists/* && apt autoremove -y
+
+ENV HOME=/home
+ENV DISPLAY :0
+
+RUN git config --global http.sslverify false
+
+RUN mkdir -p ${HOME}/git && cd ${HOME}/git \
+ && git clone -b fixes-combined https://github.com/jikespg/jikespg.git \
+ && cd jikespg/src; make clean; make
+
+USER 10001
diff --git a/org.eclipse.jdt.core/docker/jikespg/scripts/uid_entrypoint b/org.eclipse.jdt.core/docker/jikespg/scripts/uid_entrypoint
new file mode 100644
index 0000000..c44d398
--- /dev/null
+++ b/org.eclipse.jdt.core/docker/jikespg/scripts/uid_entrypoint
@@ -0,0 +1,7 @@
+#!/usr/bin/env sh
+if ! whoami > /dev/null 2>&1; then
+ if [ -w /etc/passwd ]; then
+ echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default} user:${HOME}:/sbin/nologin" >> /etc/passwd
+ fi
+fi
+exec "$@"
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/docker/push-ubuntu-jikespg.sh b/org.eclipse.jdt.core/docker/push-ubuntu-jikespg.sh
new file mode 100644
index 0000000..d577562
--- /dev/null
+++ b/org.eclipse.jdt.core/docker/push-ubuntu-jikespg.sh
@@ -0,0 +1,18 @@
+#!/bin/bash -x
+#*******************************************************************************
+# Copyright (c) 2021 IBM Corporation and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# Sravan Kumar Lakkimsetti - initial API and implementation
+#*******************************************************************************
+
+set -e
+
+docker push eclipse/platformreleng-ubuntu-gtk3-metacity:jikespg
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
index 673b448..a453660 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
@@ -92,7 +92,7 @@
*/
@Override
public boolean isCanonicalConstructor() {
- return ((this.binding.tagBits & TagBits.IsCanonicalConstructor) != 0);
+ return this.binding.isCanonicalConstructor();
}
/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
index 6edfb3e..55582ef 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
@@ -875,6 +875,19 @@
*/
public static final int MODULE_REF = 29;
+ /**
+ /**
+ * Completion is a lambda expression.
+ * This kind of completion might occur in a context like
+ * <code>Consumer consumer = ^</code> and complete it to
+ * <code>"Consumer consumer = c ->"</code> or in
+ * <code> "to Consumer consumer = c -> {}"</code>
+ *
+ * @see #getKind()
+ * @since 3.28
+ */
+ public static final int LAMBDA_EXPRESSION = 30;
+
//{ObjectTeams: new completion kinds
// when forming bitsets of completion kinds we need to fold multiple of our OT constants into the same slot.
// therefore we let them differ only by a offsets that are multiples of 32, which will be ignored during bitset operations
@@ -926,7 +939,7 @@
/**
* Generate a role type declaration overriding an implicitly inherited role from the super team.
*/
- public static final int OVERRIDE_ROLE_DECLARATION= 30;
+ public static final int OVERRIDE_ROLE_DECLARATION= 31;
// SH}
/**
@@ -943,7 +956,7 @@
*/
//{ObjectTeams: include OT completion kinds
/* orig:
- protected static final int LAST_KIND = MODULE_REF;
+ protected static final int LAST_KIND = LAMBDA_EXPRESSION;
:giro */
protected static final int LAST_KIND = OVERRIDE_ROLE_DECLARATION;
// SH}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
index 2f5a5b4..3ec5329 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
@@ -450,8 +450,8 @@
* @param flags the flags
* @return <code>true</code> if the <code>AccSealed</code> flag is included
* @see #AccSealed
- * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
- */
+ * @since 3.28
+ * */
public static boolean isSealed(int flags) {
return (flags & AccSealed) != 0;
}
@@ -462,7 +462,7 @@
* @param flags the flags
* @return <code>true</code> if the <code>AccNonSealed</code> flag is included
* @see #AccNonSealed
- * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
+ * @since 3.28
*/
public static boolean isNonSealed(int flags) {
return (flags & AccNonSealed) != 0;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
index 07f4d3d..a9ccc2a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
@@ -773,6 +773,18 @@
boolean isOnClasspath(IResource resource);
/**
+ * Returns the class path entry which contains the given resource and not explicitly excluded using an exclusion
+ * pattern, or null otherwise.
+ *
+ * @param resource
+ * the resource which may or may not on one of the class path entries.
+ * @return the class path entry which contains the given resource, or null, if it's not in any of the classpath
+ * entries, or the resource is null.
+ * @since 3.28
+ */
+ IClasspathEntry findContainingClasspathEntry(IResource resource);
+
+ /**
* Creates a new evaluation context.
* @return a new evaluation context.
*/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathAccessRule.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathAccessRule.java
index d4cb0fa..f9954f6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathAccessRule.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathAccessRule.java
@@ -30,7 +30,7 @@
}
public ClasspathAccessRule(char[] pattern, int problemId) {
- super(pattern, problemId);
+ super(JavaModelManager.getJavaModelManager().intern(pattern), problemId);
}
private static int toProblemId(int kind) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
index 459e002..514596a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
@@ -2824,38 +2824,46 @@
*/
@Override
public boolean isOnClasspath(IResource resource) {
- IPath exactPath = resource.getFullPath();
- IPath path = exactPath;
+ return findContainingClasspathEntry(resource) != null;
+ }
+ /*
+ * @see IJavaProject
+ */
+ @Override
+ public IClasspathEntry findContainingClasspathEntry(IResource resource) {
+ if (resource == null) {
+ return null;
+ }
+ final int resourceType = resource.getType();
// ensure that folders are only excluded if all of their children are excluded
- int resourceType = resource.getType();
- boolean isFolderPath = resourceType == IResource.FOLDER || resourceType == IResource.PROJECT;
-
+ final boolean isFolderPath = resourceType == IResource.FOLDER || resourceType == IResource.PROJECT;
IClasspathEntry[] classpath;
try {
classpath = this.getResolvedClasspath();
} catch(JavaModelException e){
- return false; // not a Java project
+ return null; // not a Java project
}
+ final IPath path = resource.getFullPath();
for (int i = 0; i < classpath.length; i++) {
IClasspathEntry entry = classpath[i];
IPath entryPath = entry.getPath();
- if (entryPath.equals(exactPath)) { // package fragment roots must match exactly entry pathes (no exclusion there)
- return true;
+ if (entryPath.equals(path)) { // package fragment roots must match exactly entry pathes (no exclusion there)
+ return entry;
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=276373
// When a classpath entry is absolute, convert the resource's relative path to a file system path and compare
// e.g - /P/lib/variableLib.jar and /home/P/lib/variableLib.jar when compared should return true
if (entryPath.isAbsolute()
- && entryPath.equals(ResourcesPlugin.getWorkspace().getRoot().getLocation().append(exactPath))) {
- return true;
+ && entryPath.equals(ResourcesPlugin.getWorkspace().getRoot().getLocation().append(path))) {
+ return entry;
}
if (entryPath.isPrefixOf(path)
&& !Util.isExcluded(path, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), isFolderPath)) {
- return true;
+ return entry;
}
}
- return false;
+ return null;
}
private boolean isOnClasspathEntry(IPath elementPath, boolean isFolderPath, boolean isPackageFragmentRoot, IClasspathEntry entry) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
index f093afc..5ac12c4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
@@ -11,6 +11,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - contribution for bug 337868 - [compiler][model] incomplete support for package-info.java when using SearchableEnvironment
+ * Microsoft Corporation - contribution for bug 575562 - improve completion search performance
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -568,6 +569,28 @@
* types are found relative to their enclosing type.
*/
public void findTypes(char[] prefix, final boolean findMembers, int matchRule, int searchFor, final ISearchRequestor storage, IProgressMonitor monitor) {
+ findTypes(prefix, findMembers, matchRule, searchFor, true, storage, monitor);
+ }
+
+ /**
+ * Must be used only by CompletionEngine.
+ * The progress monitor is used to be able to cancel completion operations
+ *
+ * Find the top-level types that are defined
+ * in the current environment and whose name starts with the
+ * given prefix. The prefix is a qualified name separated by periods
+ * or a simple name (ex. java.util.V or V).
+ *
+ * The types found are passed to one of the following methods (if additional
+ * information is known about the types):
+ * ISearchRequestor.acceptType(char[][] packageName, char[] typeName)
+ * ISearchRequestor.acceptClass(char[][] packageName, char[] typeName, int modifiers)
+ * ISearchRequestor.acceptInterface(char[][] packageName, char[] typeName, int modifiers)
+ *
+ * This method can not be used to find member types... member
+ * types are found relative to their enclosing type.
+ */
+ public void findTypes(char[] prefix, final boolean findMembers, int matchRule, int searchFor, final boolean resolveDocumentName, final ISearchRequestor storage, IProgressMonitor monitor) {
long start = -1;
if (NameLookup.VERBOSE)
start = System.currentTimeMillis();
@@ -671,6 +694,7 @@
matchRule, // not case sensitive
searchFor,
getSearchScope(),
+ resolveDocumentName,
typeRequestor,
FORCE_IMMEDIATE_SEARCH,
progressMonitor);
@@ -693,6 +717,7 @@
matchRule,
searchFor,
getSearchScope(),
+ resolveDocumentName,
typeRequestor,
FORCE_IMMEDIATE_SEARCH,
progressMonitor);
@@ -713,6 +738,7 @@
matchRule, // not case sensitive
searchFor,
getSearchScope(),
+ resolveDocumentName,
typeRequestor,
CANCEL_IF_NOT_READY_TO_SEARCH,
progressMonitor);
@@ -746,7 +772,7 @@
* The constructors found are passed to one of the following methods:
* ISearchRequestor.acceptConstructor(...)
*/
- public void findConstructorDeclarations(char[] prefix, int matchRule, final ISearchRequestor storage, IProgressMonitor monitor) {
+ public void findConstructorDeclarations(char[] prefix, int matchRule, final boolean resolveDocumentName, final ISearchRequestor storage, IProgressMonitor monitor) {
try {
final String excludePath;
if (this.unitToSkip != null && this.unitToSkip instanceof IJavaElement) {
@@ -879,6 +905,7 @@
simpleName,
matchRule,
getSearchScope(),
+ resolveDocumentName,
constructorRequestor,
FORCE_IMMEDIATE_SEARCH,
progressMonitor);
@@ -889,6 +916,7 @@
simpleName,
matchRule,
getSearchScope(),
+ resolveDocumentName,
constructorRequestor,
CANCEL_IF_NOT_READY_TO_SEARCH,
progressMonitor);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
index bd479df..7749d72 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -24,6 +24,7 @@
import org.eclipse.jdt.internal.compiler.parser.NLSTag;
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
+import org.eclipse.jdt.internal.compiler.util.CharDeduplication;
import org.eclipse.jdt.internal.compiler.util.Util;
public class PublicScanner implements IScanner, ITerminalSymbols {
@@ -214,41 +215,6 @@
public static final String INVALID_UNDERSCORE = "Invalid_Underscore"; //$NON-NLS-1$
public static final String UNDERSCORES_IN_LITERALS_NOT_BELOW_17 = "Underscores_In_Literals_Not_Below_17"; //$NON-NLS-1$`
- //----------------optimized identifier managment------------------
- static final char[] charArray_a = new char[] {'a'},
- charArray_b = new char[] {'b'},
- charArray_c = new char[] {'c'},
- charArray_d = new char[] {'d'},
- charArray_e = new char[] {'e'},
- charArray_f = new char[] {'f'},
- charArray_g = new char[] {'g'},
- charArray_h = new char[] {'h'},
- charArray_i = new char[] {'i'},
- charArray_j = new char[] {'j'},
- charArray_k = new char[] {'k'},
- charArray_l = new char[] {'l'},
- charArray_m = new char[] {'m'},
- charArray_n = new char[] {'n'},
- charArray_o = new char[] {'o'},
- charArray_p = new char[] {'p'},
- charArray_q = new char[] {'q'},
- charArray_r = new char[] {'r'},
- charArray_s = new char[] {'s'},
- charArray_t = new char[] {'t'},
- charArray_u = new char[] {'u'},
- charArray_v = new char[] {'v'},
- charArray_w = new char[] {'w'},
- charArray_x = new char[] {'x'},
- charArray_y = new char[] {'y'},
- charArray_z = new char[] {'z'};
-
- static final char[] initCharArray =
- new char[] {'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000'};
- static final int TableSize = 30, InternalTableSize = 6; //30*6 =210 entries
-
- public static final int OptimizedLength = 6;
- public /*static*/ final char[][][][] charArray_length =
- new char[OptimizedLength - 1][TableSize][InternalTableSize][];
// support for detecting non-externalized string literals
public static final char[] TAG_PREFIX= "//$NON-NLS-".toCharArray(); //$NON-NLS-1$
public static final int TAG_PREFIX_LENGTH= TAG_PREFIX.length;
@@ -263,21 +229,6 @@
// generic support
public boolean returnOnlyGreater = false;
- /*static*/ {
- for (int i = 0; i < OptimizedLength - 1; i++) {
- for (int j = 0; j < TableSize; j++) {
- for (int k = 0; k < InternalTableSize; k++) {
- this.charArray_length[i][j][k] = initCharArray;
- }
- }
- }
- }
-
- /*static*/ int newEntry2 = 0,
- newEntry3 = 0,
- newEntry4 = 0,
- newEntry5 = 0,
- newEntry6 = 0;
public boolean insideRecovery = false;
public static final int RoundBracket = 0;
@@ -294,6 +245,8 @@
// text block support - 13
/* package */ int rawStart = -1;
+ private CharDeduplication deduplication = CharDeduplication.getThreadLocalInstance();
+
public PublicScanner() {
this(false /*comment*/, false /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3 /*sourceLevel*/, null/*taskTag*/, null/*taskPriorities*/, true /*taskCaseSensitive*/);
}
@@ -544,24 +497,9 @@
}
int length = this.currentPosition - this.startPosition;
if (length == this.eofPosition) return this.source;
- switch (length) { // see OptimizedLength
- case 1 :
- return optimizedCurrentTokenSource1();
- case 2 :
- return optimizedCurrentTokenSource2();
- case 3 :
- return optimizedCurrentTokenSource3();
- case 4 :
- return optimizedCurrentTokenSource4();
- case 5 :
- return optimizedCurrentTokenSource5();
- case 6 :
- return optimizedCurrentTokenSource6();
- }
- char[] result = new char[length];
- System.arraycopy(this.source, this.startPosition, result, 0, length);
- return result;
+ return this.deduplication.sharedCopyOfRange(this.source, this.startPosition, this.currentPosition);
}
+
@Override
public int getCurrentTokenEndPosition(){
return this.currentPosition - 1;
@@ -2210,7 +2148,7 @@
pushLineSeparator();
//$FALL-THROUGH$
default:
- if (this.currentCharacter == '\\' && this.source[this.currentPosition++] == '"') {
+ if (this.currentCharacter == '\\' && this.source[this.currentPosition] == '"') {
this.currentPosition++;
}
this.currentCharacter = this.source[this.currentPosition++];
@@ -2516,242 +2454,6 @@
return CharOperation.isWhitespace(this.currentCharacter);
}
-final char[] optimizedCurrentTokenSource1() {
- //return always the same char[] build only once
-
- //optimization at no speed cost of 99.5 % of the singleCharIdentifier
- char charOne = this.source[this.startPosition];
- switch (charOne) {
- case 'a' :
- return charArray_a;
- case 'b' :
- return charArray_b;
- case 'c' :
- return charArray_c;
- case 'd' :
- return charArray_d;
- case 'e' :
- return charArray_e;
- case 'f' :
- return charArray_f;
- case 'g' :
- return charArray_g;
- case 'h' :
- return charArray_h;
- case 'i' :
- return charArray_i;
- case 'j' :
- return charArray_j;
- case 'k' :
- return charArray_k;
- case 'l' :
- return charArray_l;
- case 'm' :
- return charArray_m;
- case 'n' :
- return charArray_n;
- case 'o' :
- return charArray_o;
- case 'p' :
- return charArray_p;
- case 'q' :
- return charArray_q;
- case 'r' :
- return charArray_r;
- case 's' :
- return charArray_s;
- case 't' :
- return charArray_t;
- case 'u' :
- return charArray_u;
- case 'v' :
- return charArray_v;
- case 'w' :
- return charArray_w;
- case 'x' :
- return charArray_x;
- case 'y' :
- return charArray_y;
- case 'z' :
- return charArray_z;
- default :
- return new char[] {charOne};
- }
-}
-final char[] optimizedCurrentTokenSource2() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0 , c1;
- int hash = (((c0=src[start]) << 6) + (c1=src[start+1])) % TableSize;
- char[][] table = this.charArray_length[0][hash];
- int i = this.newEntry2;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0]) && (c1 == charArray[1]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry2;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0]) && (c1 == charArray[1]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[2], 0, 2);
- //newIdentCount++;
- return table[this.newEntry2 = max] = r; //(r = new char[] {c0, c1});
-}
-final char[] optimizedCurrentTokenSource3() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0, c1=src[start+1], c2;
- int hash = (((c0=src[start])<< 6) + (c2=src[start+2])) % TableSize;
-// int hash = ((c0 << 12) + (c1<< 6) + c2) % TableSize;
- char[][] table = this.charArray_length[1][hash];
- int i = this.newEntry3;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry3;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[3], 0, 3);
- //newIdentCount++;
- return table[this.newEntry3 = max] = r; //(r = new char[] {c0, c1, c2});
-}
-final char[] optimizedCurrentTokenSource4() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0, c1 = src[start+1], c2, c3 = src[start+3];
- int hash = (((c0=src[start]) << 6) + (c2=src[start+2])) % TableSize;
-// int hash = (int) (((((long) c0) << 18) + (c1 << 12) + (c2 << 6) + c3) % TableSize);
- char[][] table = this.charArray_length[2][hash];
- int i = this.newEntry4;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry4;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[4], 0, 4);
- //newIdentCount++;
- return table[this.newEntry4 = max] = r; //(r = new char[] {c0, c1, c2, c3});
-}
-final char[] optimizedCurrentTokenSource5() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0, c1 = src[start+1], c2, c3 = src[start+3], c4;
- int hash = (((c0=src[start]) << 12) +((c2=src[start+2]) << 6) + (c4=src[start+4])) % TableSize;
-// int hash = (int) (((((long) c0) << 24) + (((long) c1) << 18) + (c2 << 12) + (c3 << 6) + c4) % TableSize);
- char[][] table = this.charArray_length[3][hash];
- int i = this.newEntry5;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3])
- && (c4 == charArray[4]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry5;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3])
- && (c4 == charArray[4]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[5], 0, 5);
- //newIdentCount++;
- return table[this.newEntry5 = max] = r; //(r = new char[] {c0, c1, c2, c3, c4});
-}
-final char[] optimizedCurrentTokenSource6() {
- //try to return the same char[] build only once
-
- char[] src = this.source;
- int start = this.startPosition;
- char c0, c1 = src[start+1], c2, c3 = src[start+3], c4, c5 = src[start+5];
- int hash = (((c0=src[start]) << 12) +((c2=src[start+2]) << 6) + (c4=src[start+4])) % TableSize;
-// int hash = (int)(((((long) c0) << 32) + (((long) c1) << 24) + (((long) c2) << 18) + (c3 << 12) + (c4 << 6) + c5) % TableSize);
- char[][] table = this.charArray_length[4][hash];
- int i = this.newEntry6;
- while (++i < InternalTableSize) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3])
- && (c4 == charArray[4])
- && (c5 == charArray[5]))
- return charArray;
- }
- //---------other side---------
- i = -1;
- int max = this.newEntry6;
- while (++i <= max) {
- char[] charArray = table[i];
- if ((c0 == charArray[0])
- && (c1 == charArray[1])
- && (c2 == charArray[2])
- && (c3 == charArray[3])
- && (c4 == charArray[4])
- && (c5 == charArray[5]))
- return charArray;
- }
- //--------add the entry-------
- if (++max >= InternalTableSize) max = 0;
- char[] r;
- System.arraycopy(src, start, r= new char[6], 0, 6);
- //newIdentCount++;
- return table[this.newEntry6 = max] = r; //(r = new char[] {c0, c1, c2, c3, c4, c5});
-}
-
private void parseTags() {
int position = 0;
final int currentStartPosition = this.startPosition;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
index fbf821f..a7dcfe2 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
@@ -11,6 +11,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Technical University Berlin - extended API and implementation
+ * Microsoft Corporation - contribution for bug 575562 - improve completion search performance
*******************************************************************************/
package org.eclipse.jdt.core.search;
@@ -367,6 +368,7 @@
this.matchRule &= ~R_PREFIX_MATCH;
}
}
+
/**
* @noreference This method is not intended to be referenced by clients.
* @nooverride This method is not intended to be re-implemented or extended by clients.
@@ -2523,6 +2525,30 @@
* @nooverride This method is not intended to be re-implemented or extended by clients.
*/
public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor monitor) throws IOException {
+ findIndexMatches(index, requestor, participant, scope, true, monitor);
+}
+
+/**
+ * Query a given index for matching entries. Assumes the sender has
+ * opened the index and will close when finished.
+ *
+ * This API provides a flag to control whether to skip resolving
+ * document name for the matching entries. If a SearchPattern subclass
+ * has a different implementation of index matching, they have to
+ * override this API to support document name resolving feature.
+ *
+ * @param index the target index to query
+ * @param requestor the search requestor
+ * @param participant the search participant
+ * @param scope the search scope where the search results should be found
+ * @param resolveDocumentName whether to skip the document name resolving
+ * for the matching entries
+ * @param monitor a progress monitor
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ * @nooverride This method is not intended to be re-implemented or extended by clients.
+ */
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, boolean resolveDocumentName, IProgressMonitor monitor) throws IOException {
if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
try {
index.startQuery();
@@ -2539,10 +2565,15 @@
SearchPattern decodedResult = pattern.getBlankPattern();
decodedResult.decodeIndexKey(entry.getWord());
if (pattern.matchesDecodedKey(decodedResult)) {
- // TODO (kent) some clients may not need the document names
- String[] names = entry.getDocumentNames(index);
- for (int j = 0, n = names.length; j < n; j++)
- acceptMatch(names[j], containerPath, separator, decodedResult, requestor, participant, scope, monitor);
+ // Since resolve document name is expensive, leave the decision to the search client
+ // to decide whether to do so.
+ if (resolveDocumentName) {
+ String[] names = entry.getDocumentNames(index);
+ for (int j = 0, n = names.length; j < n; j++)
+ acceptMatch(names[j], containerPath, separator, decodedResult, requestor, participant, scope, monitor);
+ } else {
+ acceptMatch("", containerPath, separator, decodedResult, requestor, participant, scope, monitor); //$NON-NLS-1$
+ }
}
}
} finally {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
index f44d749..cce09af 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
@@ -15,6 +15,7 @@
import java.io.*;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
@@ -149,11 +150,16 @@
* If the key is null then all entries in specified categories are returned.
*/
public EntryResult[] query(char[][] categories, char[] key, int matchRule) throws IOException {
- if (this.memoryIndex.shouldMerge() && this.monitor.exitReadEnterWrite()) {
+ ReadWriteMonitor readWriteMonitor = this.monitor;
+ if(readWriteMonitor == null) {
+ // index got deleted since acquired
+ return null;
+ }
+ if (this.memoryIndex.shouldMerge() && readWriteMonitor.exitReadEnterWrite()) {
try {
save();
} finally {
- this.monitor.exitWriteEnterRead();
+ readWriteMonitor.exitWriteEnterRead();
}
}
@@ -240,6 +246,10 @@
try {
ArrayList<IndexQualifier> qualifiers = new ArrayList<>();
for(char[] category : IIndexConstants.META_INDEX_CATEGORIES) {
+ if (this.monitor == null) {
+ // index got deleted since acquired
+ return Collections.emptyList();
+ }
EntryResult[] results = query(new char[][] {category}, null,
SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
if(results != null) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
index 460e532..8f9de07 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contributions for bug 215139 and bug 295894
+ * Microsoft Corporation - Contribution for bug 575562 - improve completion search performance
*******************************************************************************/
package org.eclipse.jdt.internal.core.search;
@@ -604,10 +605,37 @@
}
public void searchAllConstructorDeclarations(
+ final char[] packageName,
+ final char[] typeName,
+ final int typeMatchRule,
+ IJavaSearchScope scope,
+ final IRestrictedAccessConstructorRequestor nameRequestor,
+ int waitingPolicy,
+ IProgressMonitor progressMonitor) throws JavaModelException {
+ searchAllConstructorDeclarations(
+ packageName,
+ typeName,
+ typeMatchRule,
+ scope,
+ true,
+ nameRequestor,
+ waitingPolicy,
+ progressMonitor);
+ }
+
+ /**
+ *
+ * Searches for constructor declarations in the given scope.
+ *
+ * @param resolveDocumentName used to tell SearchEngine whether to resolve
+ * the document name for each result entry.
+ */
+ public void searchAllConstructorDeclarations(
final char[] packageName,
final char[] typeName,
final int typeMatchRule,
IJavaSearchScope scope,
+ final boolean resolveDocumentName,
final IRestrictedAccessConstructorRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
@@ -730,6 +758,8 @@
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
+ resolveDocumentName,
+ true,
searchRequestor),
waitingPolicy,
subMonitor.split(Math.max(1000-copiesLength, 0)));
@@ -1715,12 +1745,47 @@
* for detailed comment
*/
public void searchAllTypeNames(
+ final char[] packageName,
+ final int packageMatchRule,
+ final char[] typeName,
+ final int typeMatchRule,
+ int searchFor,
+ IJavaSearchScope scope,
+ final IRestrictedAccessTypeRequestor nameRequestor,
+ int waitingPolicy,
+ IProgressMonitor progressMonitor) throws JavaModelException {
+ searchAllTypeNames(
+ packageName,
+ packageMatchRule,
+ typeName,
+ typeMatchRule,
+ searchFor,
+ scope,
+ true,
+ nameRequestor,
+ waitingPolicy,
+ progressMonitor);
+ }
+
+ /**
+ * Searches for all top-level types and member types in the given scope.
+ * The search can be selecting specific types (given a package or a type name
+ * prefix and match modes).
+ *
+ * @param resolveDocumentName used to tell SearchEngine whether to resolve
+ * the document name for each result entry.
+ *
+ * @see SearchEngine#searchAllTypeNames(char[], int, char[], int, int, IJavaSearchScope, TypeNameRequestor, int, IProgressMonitor)
+ * for detailed comment
+ */
+ public void searchAllTypeNames(
final char[] packageName,
final int packageMatchRule,
final char[] typeName,
final int typeMatchRule,
int searchFor,
IJavaSearchScope scope,
+ final boolean resolveDocumentName,
final IRestrictedAccessTypeRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
@@ -1859,12 +1924,15 @@
};
SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
+
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
+ resolveDocumentName,
+ true,
searchRequestor),
waitingPolicy,
subMonitor.split(Math.max(1000-copiesLength, 0)));
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
index 32668ee..7054192 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Microsoft Corporation - contribution for bug 575562 - improve completion search performance
*******************************************************************************/
package org.eclipse.jdt.internal.core.search;
@@ -53,6 +54,8 @@
protected IJavaSearchScope scope;
protected SearchParticipant participant;
protected IndexQueryRequestor requestor;
+protected boolean resolveDocumentForJar;
+protected boolean resolveDocumentForSourceFiles;
protected boolean areIndexesReady;
protected AtomicLong executionTime;
boolean parallel;
@@ -61,12 +64,27 @@
public static final boolean ENABLE_PARALLEL_SEARCH_DEFAULT = true;
public PatternSearchJob(SearchPattern pattern, SearchParticipant participant, IJavaSearchScope scope, IndexQueryRequestor requestor) {
+ this(pattern, participant, scope, true, true, requestor);
+}
+
+/**
+ * Create a search job with the specified search pattern.
+ *
+ * @param resolveDocumentForJar whether to resolve the document name of a result entry
+ * if it comes to a JAR library.
+ * @param resolveDocumentForSourceFiles whether to resolve the document name of a result entry
+ * if it comes from a project's source files.
+ */
+public PatternSearchJob(SearchPattern pattern, SearchParticipant participant, IJavaSearchScope scope, final boolean resolveDocumentForJar, final boolean resolveDocumentForSourceFiles, IndexQueryRequestor requestor) {
this.executionTime = new AtomicLong(0);
this.pattern = pattern;
this.participant = participant;
this.scope = scope;
this.requestor = requestor;
+ this.resolveDocumentForJar = resolveDocumentForJar;
+ this.resolveDocumentForSourceFiles = resolveDocumentForSourceFiles;
}
+
@Override
public boolean belongsTo(String jobFamily) {
return true;
@@ -211,7 +229,16 @@
searchPattern = clone(searchPattern);
searchScope = clone(searchScope);
}
- MatchLocator.findIndexMatches(searchPattern, index, queryRequestor, this.participant, searchScope, progressMonitor);
+
+ boolean isFromJar = index.isIndexForJar();
+ boolean resolveDocumentName = (isFromJar && this.resolveDocumentForJar)
+ || (!isFromJar && this.resolveDocumentForSourceFiles);
+ if (resolveDocumentName) {
+ // fall back to the default behavior in case some pattern implementation doesn't adapt to the new index search API.
+ MatchLocator.findIndexMatches(searchPattern, index, queryRequestor, this.participant, searchScope, progressMonitor);
+ } else {
+ MatchLocator.findIndexMatches(searchPattern, index, queryRequestor, this.participant, searchScope, false, progressMonitor);
+ }
this.executionTime.addAndGet(System.currentTimeMillis() - start);
return COMPLETE;
} catch (IOException e) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index 1a53016..540556e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -1758,11 +1758,15 @@
iterator.remove();
}
}
- if(index == null) {
+ if (index == null) {
return true;
}
+ if (index.monitor == null) {
+ // index got deleted since acquired
+ continue;
+ }
File indexFile = index.getIndexFile();
- if(indexFile == null) {
+ if (indexFile == null) {
continue;
}
if (VERBOSE) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/IntersectingPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/IntersectingPattern.java
index 448eed9..e73eda3 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/IntersectingPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/IntersectingPattern.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Microsoft Corporation - adapt to the new index match API
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
@@ -30,6 +31,7 @@
public IntersectingPattern(int patternKind, int matchRule) {
super(patternKind, matchRule);
}
+
@Override
public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
@@ -77,6 +79,12 @@
if (names[i] != null)
acceptMatch((String) names[i], containerPath, separator, null/*no pattern*/, requestor, participant, scope, progressMonitor); // AndPatterns cannot provide the decoded result
}
+
+@Override
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, boolean resolveDocumentName, IProgressMonitor progressMonitor) throws IOException {
+ findIndexMatches(index, requestor, participant, scope, progressMonitor);
+}
+
/**
* Returns whether another query must be done.
*/
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
index 7bd60b0..01b6ff8 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Microsoft Corporation - adapt to the new index match API
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
@@ -70,6 +71,12 @@
throw new OperationCanceledException();
}
}
+
+@Override
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, boolean resolveDocumentName, IProgressMonitor progressMonitor) {
+ findIndexMatches(index, requestor, participant, scope, progressMonitor);
+}
+
@Override
protected StringBuffer print(StringBuffer output) {
if (this.findDeclarations) {
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 0129c95..0e90cc7 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
@@ -14,6 +14,7 @@
* Technical University Berlin - extended API and implementation
* Stephan Herrmann - Contribution for
* Bug 377883 - NPE on open Call Hierarchy
+ * Microsoft Corporation - Contribution for bug 575562 - improve completion search performance
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
@@ -361,6 +362,13 @@
pattern.findIndexMatches(index, requestor, participant, scope, monitor);
}
+/**
+ * Query a given index for matching entries. Assumes the sender has opened the index and will close when finished.
+ */
+public static void findIndexMatches(SearchPattern pattern, Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, boolean resolveDocumentName, IProgressMonitor monitor) throws IOException {
+ pattern.findIndexMatches(index, requestor, participant, scope, resolveDocumentName, monitor);
+}
+
public static IJavaElement getProjectOrJar(IJavaElement element) {
while (!(element instanceof IJavaProject) && !(element instanceof JarPackageFragmentRoot)) {
element = element.getParent();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
index 386435d..ad2bcb2 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Microsoft Corporation - adapt to the new index match API
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
@@ -70,6 +71,18 @@
}
@Override
+ public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, boolean resolveDocumentName, IProgressMonitor progressMonitor) throws IOException {
+ // per construction, OR pattern can only be used with a PathCollector (which already gather results using a set)
+ try {
+ index.startQuery();
+ for (int i = 0, length = this.patterns.length; i < length; i++)
+ this.patterns[i].findIndexMatches(index, requestor, participant, scope, resolveDocumentName, progressMonitor);
+ } finally {
+ index.stopQuery();
+ }
+ }
+
+ @Override
public SearchPattern getBlankPattern() {
return null;
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeParameterPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeParameterPattern.java
index e3d2083..b2c6ff0 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeParameterPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeParameterPattern.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Microsoft Corporation - adapt to the new index match API
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
@@ -118,6 +119,11 @@
}
@Override
+ public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, boolean resolveDocumentName, IProgressMonitor progressMonitor) {
+ findIndexMatches(index, requestor, participant, scope, progressMonitor);
+ }
+
+ @Override
protected StringBuffer print(StringBuffer output) {
if (this.findDeclarations) {
output.append(this.findReferences
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
index d0eadca..490ce51 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
@@ -48,6 +48,8 @@
private int awaitingClients = 0;
+ private final Object idleMonitor = new Object();
+
/**
* Invoked exactly once, in background, before starting processing any job
*/
@@ -251,6 +253,11 @@
throw new OperationCanceledException();
IJob currentJob = currentJob();
// currentJob can be null when jobs have been added to the queue but job manager is not enabled
+ if (currentJob != null ) {
+ synchronized (this.idleMonitor) {
+ this.idleMonitor.notifyAll(); // wake up idle sleepers
+ }
+ }
if (currentJob != null && currentJob != previousJob) {
if (VERBOSE)
Util.verbose("-> NOT READY - waiting until ready - " + searchJob);//$NON-NLS-1$
@@ -414,7 +421,9 @@
if (job == null) {
notifyIdle(System.currentTimeMillis() - idlingStart);
// just woke up, delay before processing any new jobs, allow some time for the active thread to finish
- Thread.sleep(500);
+ synchronized (this.idleMonitor) {
+ this.idleMonitor.wait(500); // avoid sleep fixed time
+ }
continue;
}
if (VERBOSE) {
@@ -440,7 +449,9 @@
if (VERBOSE) {
Util.verbose("WAITING after job - " + job); //$NON-NLS-1$
}
- Thread.sleep(5);
+ synchronized (this.idleMonitor) {
+ this.idleMonitor.wait(5); // avoid sleep fixed time
+ }
}
}
} catch (InterruptedException e) { // background indexing was interrupted