diff options
| author | Stephan Herrmann | 2021-05-22 10:37:30 +0000 |
|---|---|---|
| committer | Jay Arthanareeswaran | 2021-05-24 09:47:10 +0000 |
| commit | e211a44735f4142c81518de31a4da690328c1c35 (patch) | |
| tree | 6b00ac91201cc4f3415807e0f25ade4818cfa647 | |
| parent | b0f1636c9828e2afa0492327b2fa0e45cf131848 (diff) | |
| download | eclipse.jdt.core-e211a44735f4142c81518de31a4da690328c1c35.tar.gz eclipse.jdt.core-e211a44735f4142c81518de31a4da690328c1c35.tar.xz eclipse.jdt.core-e211a44735f4142c81518de31a4da690328c1c35.zip | |
Bug 573702 - Wrong completions for parameter on a method chainI20210524-1800I20210524-0600
Change-Id: I48ae23090a79c5d473d7793ec11d96df4c438d85
Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/180899
Tested-by: JDT Bot <jdt-bot@eclipse.org>
Reviewed-by: Jay Arthanareeswaran <jarthana@in.ibm.com>
Reviewed-by: Gayan Perera <gayanper@gmail.com>
2 files changed, 197 insertions, 3 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 4d57bdc8a3..0411c067d8 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 @@ -26231,4 +26231,148 @@ public void testBug573632c() throws Exception { "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, wait, (millis, nanos), 60}", requestor.getResults()); } +public void testBug573702() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "Completion/src/App.java", + "import java.util.Collection;\n" + + "import java.util.Map;\n" + + "\n" + + "interface ObjectProperty<T> {\n" + + " void addListener(SingleFireInvalidationListener singleFireInvalidationListener);\n" + + "}\n" + + "class SingleFireInvalidationListener {\n" + + " public SingleFireInvalidationListener(Collection<String> list) { }\n" + + "}\n" + + "public class App {\n" + + "\n" + + " public static void boo(Map<String, String> data) {\n" + + " System.out.println(\"PopOver direct buffer delayed patch installation started\");\n" + + " App.getDataProperty().addListener(new SingleFireInvalidationListener(data.values()));\n" + + " System.out.println(\"PopOver direct buffer delayed patch installation done\");\n" + + " }\n" + + "\n" + + " public static ObjectProperty<Map<String, String>> getDataProperty() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + String str = this.workingCopies[0].getSource(); + String completeBehind = "new SingleFireInvalidationListener(data"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); + assertResults( + "data[LOCAL_VARIABLE_REF]{data, null, LMap;, data, null, 56}", + requestor.getResults()); +} +public void testBug573702_fieldRef() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "Completion/src/App.java", + "import java.util.Collection;\n" + + "import java.util.Map;\n" + + "\n" + + "interface ObjectProperty<T> {\n" + + " void addListener(SingleFireInvalidationListener singleFireInvalidationListener);\n" + + "}\n" + + "class SingleFireInvalidationListener {\n" + + " public SingleFireInvalidationListener(Collection<String> list) { }\n" + + "}\n" + + "public class App {\n" + + " Map<String, String> data;\n" + + " public void boo() {\n" + + " System.out.println(\"PopOver direct buffer delayed patch installation started\");\n" + + " App.getDataProperty().addListener(new SingleFireInvalidationListener(this.data.values()));\n" + + " System.out.println(\"PopOver direct buffer delayed patch installation done\");\n" + + " }\n" + + "\n" + + " public static ObjectProperty<Map<String, String>> getDataProperty() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + String str = this.workingCopies[0].getSource(); + String completeBehind = "new SingleFireInvalidationListener(this.data"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); + assertResults( + "data[FIELD_REF]{data, LApp;, LMap;, data, null, 64}", + requestor.getResults()); +} +public void testBug573702_qualifiedName() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "Completion/src/App.java", + "import java.util.Collection;\n" + + "import java.util.Map;\n" + + "\n" + + "interface ObjectProperty<T> {\n" + + " void addListener(SingleFireInvalidationListener singleFireInvalidationListener);\n" + + "}\n" + + "class SingleFireInvalidationListener {\n" + + " public SingleFireInvalidationListener(Collection<String> list) { }\n" + + "}\n" + + "public class App {\n" + + " static Map<String, String> data;\n" + + " public void boo() {\n" + + " System.out.println(\"PopOver direct buffer delayed patch installation started\");\n" + + " App.getDataProperty().addListener(new SingleFireInvalidationListener(App.data.values()));\n" + + " System.out.println(\"PopOver direct buffer delayed patch installation done\");\n" + + " }\n" + + "\n" + + " public static ObjectProperty<Map<String, String>> getDataProperty() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + String str = this.workingCopies[0].getSource(); + String completeBehind = "new SingleFireInvalidationListener(App.data"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); + assertResults( + "data[FIELD_REF]{data, LApp;, LMap;, data, null, 55}", + requestor.getResults()); +} +public void testBug573702_qualifiedName_firstSegment() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "Completion/src/App.java", + "import java.util.Collection;\n" + + "import java.util.Map;\n" + + "\n" + + "interface ObjectProperty<T> {\n" + + " void addListener(SingleFireInvalidationListener singleFireInvalidationListener);\n" + + "}\n" + + "class SingleFireInvalidationListener {\n" + + " public SingleFireInvalidationListener(Collection<String> list) { }\n" + + "}\n" + + "public class App {\n" + + " static Map<String, String> data;\n" + + " public void boo() {\n" + + " System.out.println(\"PopOver direct buffer delayed patch installation started\");\n" + + " App.getDataProperty().addListener(new SingleFireInvalidationListener(App.data.values()));\n" + + " System.out.println(\"PopOver direct buffer delayed patch installation done\");\n" + + " }\n" + + "\n" + + " public static ObjectProperty<Map<String, String>> getDataProperty() {\n" + + " return null;\n" + + " }\n" + + "}\n"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + String str = this.workingCopies[0].getSource(); + String completeBehind = "new SingleFireInvalidationListener(App"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); + assertResults( + "App[TYPE_REF]{App, , LApp;, null, null, 56}", + requestor.getResults()); +} } 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 ace2ddef20..68bb0454dd 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 @@ -5411,11 +5411,61 @@ protected TypeReference getTypeReferenceForGenericType(int dim, int identifierLe } @Override protected NameReference getUnspecifiedReference(boolean rejectTypeAnnotations) { - NameReference nameReference = super.getUnspecifiedReference(rejectTypeAnnotations); + // code copied from super, but conditionally creating CompletionOn* nodes: + + /* build a (unspecified) NameReference which may be qualified*/ + if (rejectTypeAnnotations) { // Compensate for overpermissive grammar. + consumeNonTypeUseName(); + } + int length; + NameReference ref; + if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) { + // single variable reference + char[] token = this.identifierStack[this.identifierPtr]; + long position = this.identifierPositionStack[this.identifierPtr--]; + int start = (int) (position >>> 32), end = (int) position; + if (this.assistNode == null && start < this.cursorLocation && end >= this.cursorLocation) { + ref = new CompletionOnSingleNameReference(token, position, isInsideAttributeValue()); + this.assistNode = ref; + } else { + ref = new SingleNameReference(token, position); + } + } else { + //Qualified variable reference + char[][] tokens = new char[length][]; + this.identifierPtr -= length; + System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); + long[] positions = new long[length]; + System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); + int start = (int) (positions[0] >>> 32), end = (int) positions[length-1]; + if (this.assistNode == null && start < this.cursorLocation && end >= this.cursorLocation) { + // find the token at cursorLocation: + int previousCount = 0; + for (int i=0; i<length; i++) { + if (((int) positions[i]) < this.cursorLocation) + previousCount = i + 1; + } + if (previousCount > 0) { + char[][] subset = new char[previousCount][]; + System.arraycopy(tokens, 0, subset, 0, previousCount); + ref = new CompletionOnQualifiedNameReference(subset, tokens[previousCount], positions, isInsideAttributeValue()); + } else { + // with only one token up-to cursorLocation avoid a bogus qualifiedNameReference (simply skipping the remainder): + ref = new CompletionOnSingleNameReference(tokens[0], positions[0], isInsideAttributeValue()); + } + this.assistNode = ref; + } else { + ref = + new QualifiedNameReference(tokens, + positions, + (int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart + (int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd + } + } if (this.record) { - recordReference(nameReference); + recordReference(ref); } - return nameReference; + return ref; } @Override protected void consumePostfixExpression() { |
