Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2021-10-17 21:43:36 +0000
committerStephan Herrmann2021-10-21 19:11:23 +0000
commitce59f244f3c0c78d1953b77e8d3652368d985c3a (patch)
treea548ce602330fbadb6cf326ca7b7db36c142f9e5
parent437144de085992ac398c6582dce05c16b64324db (diff)
downloadeclipse.jdt.core-ce59f244f3c0c78d1953b77e8d3652368d985c3a.tar.gz
eclipse.jdt.core-ce59f244f3c0c78d1953b77e8d3652368d985c3a.tar.xz
eclipse.jdt.core-ce59f244f3c0c78d1953b77e8d3652368d985c3a.zip
Bug 575631 - [content assist] missing static method proposals in
conditional, before variable declaration Change-Id: Ib6cb4b149bd2fa720103383c43dabb2e25a9b5a7 Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/186576 Tested-by: JDT Bot <jdt-bot@eclipse.org> Reviewed-by: Stephan Herrmann <stephan.herrmann@berlin.de>
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/AllocationExpressionCompletionTest.java180
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ExplicitConstructorInvocationCompletionTest.java16
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/MethodInvocationCompletionTest.java30
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java4
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java257
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java106
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java5
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java65
8 files changed, 559 insertions, 104 deletions
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 847f7721ef..30694438a4 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 @@ public static Test suite() {
/*
* 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 @@ public void testInIfStatement() {
// 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 @@ public void testInIfStatement() {
* 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 @@ public void testNoQualificationQualifiedTypeName() {
// 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 @@ public void testNoQualificationQualifiedTypeName() {
* 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 @@ public void testNoQualificationSimpleTypeName() {
// 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 @@ public void testNoQualificationSimpleTypeName() {
*
* 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 @@ public void testQualifiedWithName() {
// 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 @@ public void testQualifiedWithName() {
*
* 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 @@ public void testQualifiedWithPrimary() {
// 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 c0a0849653..2d89e672e6 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 @@ public void testPrimarySuper() {
// completeBehind:
"super(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnExplicitConstructorCall:primary().super(1, 2)>;",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" public class InnerBar {\n" +
@@ -58,7 +58,7 @@ public void testPrimarySuper() {
" }\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 @@ public void testPrimaryThis() {
// completeBehind:
"this(1, 2,",
// expectedCompletionNodeToString:
- "<CompleteOnExplicitConstructorCall:primary().this(1, 2)>;",
+ "<CompleteOnName:>",
// expectedUnitDisplayString:
"class Bar {\n" +
" public class InnerBar {\n" +
@@ -107,7 +107,7 @@ public void testPrimaryThis() {
" }\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 @@ public void testSuper() {
// 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 @@ public void testThis() {
// 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 38dca1c05b..3f061ee575 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 @@ public void testBeforeLastParameter() {
// 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 @@ public void testLabeledWithExpressionReceiver() {
// 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 @@ public void testLabeledWithoutReceiver() {
// 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 @@ public void testWithNameReceiverAndTwoArgs() {
// 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 @@ public void testWithQualifiedNameReceiver() {
// 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.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 eaff34a610..b0e1172b81 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
@@ -19295,9 +19295,7 @@ public void testStaticMembers1() throws JavaModelException {
"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/CompletionTests3.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java
index d6b8dd60ff..a18ac50a12 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 @@ public void testBug575397a() throws Exception {
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 @@ public void testBug575397c() throws Exception {
"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 @@ public void testBug575397c() throws Exception {
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/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
index 8e9491893c..234c953c78 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
@@ -2000,7 +2000,7 @@ public final class CompletionEngine
} 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) {
@@ -3581,8 +3581,15 @@ public final class CompletionEngine
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
@@ -3596,20 +3603,20 @@ public final class CompletionEngine
(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);
}
}
}
@@ -3626,7 +3633,7 @@ public final class CompletionEngine
scope,
fieldsFound,
methodsFound,
- ref,
+ site,
scope,
false,
false,
@@ -3640,15 +3647,17 @@ public final class CompletionEngine
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) ||
@@ -3656,7 +3665,7 @@ public final class CompletionEngine
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 {
@@ -3669,7 +3678,7 @@ public final class CompletionEngine
findFieldsAndMethodsFromMissingType(
localVariableBinding.declaration.type,
localVariableBinding.declaringScope,
- ref,
+ site,
scope);
} else {
// complete field members with missing fields type
@@ -3679,7 +3688,7 @@ public final class CompletionEngine
// f.|
// }
// }
- findFieldsAndMethodsFromMissingFieldType(ref.tokens[0], scope, ref, insideTypeAnnotation);
+ findFieldsAndMethodsFromMissingFieldType(tokens[0], scope, site, insideTypeAnnotation);
}
}
@@ -3687,7 +3696,6 @@ public final class CompletionEngine
}
} else if (qualifiedBinding instanceof ReferenceBinding && !(qualifiedBinding instanceof TypeVariableBinding)) {
- boolean isInsideAnnotationAttribute = ref.isInsideAnnotationAttribute;
ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding;
setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
@@ -3695,7 +3703,7 @@ public final class CompletionEngine
this.completionToken,
receiverType,
scope,
- ref,
+ site,
isInsideAnnotationAttribute,
null,
null,
@@ -3704,7 +3712,7 @@ public final class CompletionEngine
} 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
@@ -3712,7 +3720,7 @@ public final class CompletionEngine
}
}
- 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;
@@ -3730,6 +3738,8 @@ public final class CompletionEngine
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);
@@ -3744,16 +3754,6 @@ public final class CompletionEngine
}
} 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);
@@ -3782,6 +3782,7 @@ public final class CompletionEngine
null,
null,
false);
+ haveTypeProposals = typesFound.size() > 0;
}
} else if (qualifiedBinding instanceof PackageBinding) {
@@ -3790,24 +3791,17 @@ public final class CompletionEngine
// 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);
}
}
}
@@ -3815,7 +3809,7 @@ public final class CompletionEngine
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) {
@@ -7260,7 +7254,7 @@ public final class CompletionEngine
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;
@@ -10080,7 +10074,9 @@ public final class CompletionEngine
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;
@@ -10161,6 +10157,16 @@ public final class CompletionEngine
}
}
+ 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,
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 4ab064be45..c69faafc84 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 class CompletionOnQualifiedTypeReference extends QualifiedTypeReference {
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 @@ public CompletionOnQualifiedTypeReference(char[][] previousIdentifiers, char[] c
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 310dbc5f38..7485157341 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
@@ -19,6 +19,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.
@@ -4020,11 +4021,22 @@ protected int fetchNextToken() throws InvalidInputException {
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:
@@ -4043,6 +4055,47 @@ protected int fetchNextToken() throws InvalidInputException {
}
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) {
@@ -5062,7 +5115,7 @@ public TypeReference createQualifiedAssistTypeReference(char[][] previousIdentif
if (ref != null)
return ref;
return new CompletionOnQualifiedTypeReference(previousIdentifiers, assistName, positions,
- CompletionOnQualifiedTypeReference.K_TYPE, this.currentToken);
+ CompletionOnQualifiedTypeReference.K_TYPE);
}
}
@Override

Back to the top