Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2021-05-20 20:25:08 +0000
committerJay Arthanareeswaran2021-05-24 04:37:34 +0000
commit0904799f18b393b84b7d7f69b95f1a1cd7534343 (patch)
tree85a96cebd770ed92a194cd58e4e7064f663b3dd4
parentf405e82c76aed68376e8e17e0ebf3b01f613d19e (diff)
downloadeclipse.jdt.core-0904799f18b393b84b7d7f69b95f1a1cd7534343.tar.gz
eclipse.jdt.core-0904799f18b393b84b7d7f69b95f1a1cd7534343.tar.xz
eclipse.jdt.core-0904799f18b393b84b7d7f69b95f1a1cd7534343.zip
Bug 573632 - Content assist is not working anymore after "if"
Change-Id: I3eb8a982fda8fbf5f70be5ce4dff647b94184d13 Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de> Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/180822 Tested-by: Jay Arthanareeswaran <jarthana@in.ibm.com> Reviewed-by: Jay Arthanareeswaran <jarthana@in.ibm.com>
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java153
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests9.java38
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java41
3 files changed, 226 insertions, 6 deletions
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 ec723935d3..4d57bdc8a3 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
@@ -26078,4 +26078,157 @@ public void testBug496354() throws Exception {
"val2[ANNOTATION_ATTRIBUTE_REF]{val2=, LT;, I, val2, null, 52}",
requestor.getResults());
}
+public void testBug573632() throws Exception {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Foo.java",
+ "package test;\n" +
+ "public class Foo {\n" +
+ " Foo f;\n" +
+ " public void foo() {\n" +
+ " if (f != null) {\n" +
+ " f.\n" +
+ " f = null;\n" +
+ " }\n" +
+ " };\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "f.";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.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" +
+ "f[FIELD_REF]{f, LFoo;, LFoo;, f, null, 60}\n" +
+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 60}\n" +
+ "foo[METHOD_REF]{foo(), LFoo;, ()V, foo, null, 60}\n" +
+ "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class;, 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" +
+ "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());
+}
+public void testBug573632a() throws Exception {
+ // variation: nested ifs
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Foo.java",
+ "package test;\n" +
+ "public class Foo {\n" +
+ " Foo f;\n" +
+ " public void foo() {\n" +
+ " if (f != null) {\n" +
+ " if (f != null) {\n" +
+ " f.\n" +
+ " f = null;\n" +
+ " }\n" +
+ " }\n" +
+ " };\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "f.";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.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" +
+ "f[FIELD_REF]{f, LFoo;, LFoo;, f, null, 60}\n" +
+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 60}\n" +
+ "foo[METHOD_REF]{foo(), LFoo;, ()V, foo, null, 60}\n" +
+ "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class;, 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" +
+ "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());
+}
+public void testBug573632b() throws Exception {
+ // variation: for
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Foo.java",
+ "package test;\n" +
+ "public class Foo {\n" +
+ " Foo f;\n" +
+ " public void foo() {\n" +
+ " for (int i = 0; f != null; i++) {\n" +
+ " f.\n" +
+ " f = null;\n" +
+ " }\n" +
+ " };\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "f.";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.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" +
+ "f[FIELD_REF]{f, LFoo;, LFoo;, f, null, 60}\n" +
+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 60}\n" +
+ "foo[METHOD_REF]{foo(), LFoo;, ()V, foo, null, 60}\n" +
+ "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class;, 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" +
+ "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());
+}
+public void testBug573632c() throws Exception {
+ // variation: while
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "Completion/src/Foo.java",
+ "package test;\n" +
+ "public class Foo {\n" +
+ " Foo f;\n" +
+ " public void foo() {\n" +
+ " while (f != null) {\n" +
+ " f.\n" +
+ " f = null;\n" +
+ " }\n" +
+ " };\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "f.";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.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" +
+ "f[FIELD_REF]{f, LFoo;, LFoo;, f, null, 60}\n" +
+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 60}\n" +
+ "foo[METHOD_REF]{foo(), LFoo;, ()V, foo, null, 60}\n" +
+ "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class;, 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" +
+ "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());
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests9.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests9.java
index 6a9596b017..a9420b7ba8 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests9.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests9.java
@@ -1636,4 +1636,42 @@ public void testBug560606() throws CoreException {
deleteProject(project1);
}
}
+public void testBug573632d() throws Exception {
+ IJavaProject project1 = createJavaProject("Completion9_1", new String[] {"src"}, new String[] {"JCL19_LIB", "org.eclipse.jdt.core.tests.model.TEST_CONTAINER"}, "bin", "9");
+ try {
+ project1.open(null);
+ CompletionResult result = complete(
+ "/Completion9_1/src/Foo.java",
+ "package test;\n" +
+ "import java.io.InputStream;\n" +
+ "public class Foo {\n" +
+ " Foo f;\n" +
+ " public void foo() {\n" +
+ " InputStream is = new InputStream(null);\n" +
+ " try (is) {\n" +
+ " f.\n" +
+ " f = null;\n" +
+ " }\n" +
+ " };\n" +
+ "}\n",
+ "f.");
+ 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" +
+ "f[FIELD_REF]{f, LFoo;, LFoo;, f, null, 60}\n" +
+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 60}\n" +
+ "foo[METHOD_REF]{foo(), LFoo;, ()V, foo, 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" +
+ "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}",
+ result.proposals);
+ } finally {
+ deleteProject(project1);
+ }
+}
} \ No newline at end of file
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 de79ff84c0..ace2ddef20 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
@@ -4012,8 +4012,8 @@ protected void consumeSwitchLabeledBlock() {
protected int fetchNextToken() throws InvalidInputException {
int token = this.scanner.getNextToken();
if (!this.diet && token != TerminalTokens.TokenNameEOF) {
- if (!requireExtendedRecovery() && this.expressionPtr == -1) {
- if (this.scanner.currentPosition > this.cursorLocation) {
+ if (!requireExtendedRecovery() && this.scanner.currentPosition > this.cursorLocation) {
+ if (!hasPendingExpression(token)) {
this.scanner.eofPosition = this.cursorLocation + 1; // revert to old strategy where we stop parsing right at the cursor
// stop immediately or deferred?
@@ -4028,6 +4028,26 @@ protected int fetchNextToken() throws InvalidInputException {
}
return token;
}
+private boolean hasPendingExpression(int token) {
+ if (this.expressionPtr == -1)
+ return false;
+ if (token == TerminalTokens.TokenNameDOT) {
+ // at '.' we are more eager to send early EOF to avoid seeing a qualified type reference in this pattern:
+ // foo.|
+ // bar ...
+ Expression expression = this.expressionStack[this.expressionPtr];
+ int elPtr = this.elementPtr;
+ while (elPtr >= 0) {
+ if (this.elementKindStack[elPtr] == K_BLOCK_DELIMITER) {
+ if (this.elementObjectInfoStack[elPtr] == expression) {
+ return false; // top expr on expressionStack belongs to a block statement (e.g., an if-condition)
+ }
+ }
+ elPtr--;
+ }
+ }
+ return true;
+}
@Override
protected void consumeToken(int token) {
if(this.isFirst) {
@@ -4291,10 +4311,19 @@ protected void consumeToken(int token) {
if (kind == K_CONTROL_STATEMENT_DELIMITER) {
int info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
popElement(K_CONTROL_STATEMENT_DELIMITER);
- if (info == IF) {
- pushOnElementStack(K_BLOCK_DELIMITER, IF, this.expressionStack[this.expressionPtr]);
- } else {
- pushOnElementStack(K_BLOCK_DELIMITER, info);
+ switch (info) {
+ case IF:
+ // include top-expression of these just for the benefit of hasPendingExpression():
+ // (TRY is not included, even Java9-t-w-r doesn't own an *expression*)
+ case FOR:
+ case WHILE:
+ if (this.expressionPtr > -1) {
+ pushOnElementStack(K_BLOCK_DELIMITER, info, this.expressionStack[this.expressionPtr]);
+ break;
+ }
+ //$FALL-THROUGH$
+ default:
+ pushOnElementStack(K_BLOCK_DELIMITER, info);
}
} else {
switch(previous) {

Back to the top