diff options
author | Gayan Perera | 2021-02-07 20:09:28 +0000 |
---|---|---|
committer | Vikas Chandra | 2021-02-11 12:54:24 +0000 |
commit | d890922f01a874dd5cafce5db8dfb5bae47b2f3c (patch) | |
tree | 1567e24a493e52db624cce2bad1f2279c7f4e80d | |
parent | 4c1496dfbd11b3ad81e483bf468882e56f00e870 (diff) | |
download | eclipse.jdt.core-d890922f01a874dd5cafce5db8dfb5bae47b2f3c.tar.gz eclipse.jdt.core-d890922f01a874dd5cafce5db8dfb5bae47b2f3c.tar.xz eclipse.jdt.core-d890922f01a874dd5cafce5db8dfb5bae47b2f3c.zip |
Bug570593 : Fix completions on nested parameterized type definitions
When invoking on nested parameterized type definitions like
Map<Long, Map<K,V>> completions were not provided to nested
parameterized type indexes other than the last. This issue fix that
problem by properly returning the correct parent node from
CompletionNodeDetector
Change-Id: I6bf59ba4e5d2af82f71486cc6d30ec4880bde080
Signed-off-by: Gayan Perera <gayanper@gmail.com>
2 files changed, 301 insertions, 0 deletions
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 f38b48b005..bb6c03f1e4 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 @@ -3760,4 +3760,291 @@ public void testCompletionConstructorRelevance() throws JavaModelException { "LinkedBlockingQueue[CONSTRUCTOR_INVOCATION]{(), Ljava.util.concurrent.LinkedBlockingQueue;, (Ljava.util.Collection<+TE;>;)V, LinkedBlockingQueue, (arg0), " + expectedConstructorRelevance + "}", requestor.getResults()); } + +public void testBug570593_SingleTypeParam() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.List;\n" + + "\n" + + "public class Bug570593 {\n" + + " private List<XBug570593>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_MultipleTypeParams_OnFirstTP() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.Map;\n" + + "\n" + + "public class Bug570593 {\n" + + " private Map<XBug570593,V>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_MultipleTypeParams_OnSecondTP() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.Map;\n" + + "\n" + + "public class Bug570593 {\n" + + " private Map<Long,XBug570593>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_SingleTypeParam_NestedSingleParam() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.List;\n" + + "\n" + + "public class Bug570593 {\n" + + " private List<List<XBug570593>>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_SingleTypeParam_NestedMultiParams_OnFirst() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.List;\n" + + "import java.util.Map;\n" + + "\n" + + "public class Bug570593 {\n" + + " private List<Map<XBug570593,V>>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_SingleTypeParam_NestedMultiParams_OnSecond() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.List;\n" + + "import java.util.Map;\n" + + "\n" + + "public class Bug570593 {\n" + + " private List<Map<Long,XBug570593>>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_MultiTypeParam_OnFirst_NestedSingleParam() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.List;\n" + + "import java.util.Map;\n" + + "\n" + + "public class Bug570593 {\n" + + " private Map<List<XBug570593>,V>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_MultiTypeParam_OnSecond_NestedSingleParam() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.List;\n" + + "import java.util.Map;\n" + + "\n" + + "public class Bug570593 {\n" + + " private Map<Long,List<XBug570593>>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_MultiTypeParam_NestedMultiParam_OnFirst() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.List;\n" + + "import java.util.Map;\n" + + "\n" + + "public class Bug570593 {\n" + + " private Map<Long,Map<XBug570593,R>>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + +public void testBug570593_MultiTypeParam_NestedMultiParam_OnSecond() throws JavaModelException { + this.workingCopies = new ICompilationUnit[2]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/Bug570593.java", + "import java.util.List;\n" + + "import java.util.Map;\n" + + "\n" + + "public class Bug570593 {\n" + + " private Map<Long,Map<String,XBug570593>>\n" + + "}"); + this.workingCopies[1] = getWorkingCopy( + "/Completion/src/XBug570593Type.java", + "\n" + + "public class XBug570593Type {\n" + + "}"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "XBug570593"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + assertResults( + "XBug570593Type[TYPE_REF]{XBug570593Type, , LXBug570593Type;, null, null, 72}", + requestor.getResults()); +} + } diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java index a8f214a300..04befdd0e7 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java @@ -13,6 +13,8 @@ *******************************************************************************/ package org.eclipse.jdt.internal.codeassist.complete; +import java.util.stream.Stream; + import org.eclipse.jdt.internal.compiler.*; import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.lookup.*; @@ -381,8 +383,20 @@ public class CompletionNodeDetector extends ASTVisitor { && !(astNode instanceof ConditionalExpression && ((ConditionalExpression) astNode).valueIfTrue == this.searchedNode) && !(astNode instanceof ConditionalExpression && ((ConditionalExpression) astNode).valueIfFalse == this.searchedNode)) { this.parent = astNode; + return; } } + + // when we have recovering node like private Map<String, Function<I,R>> the visitor actually endVisit on I and + // R when completions are requested at I. The above logic actually identify R as a parent since the R is visited + // and endVisited after founding that I was the searched node. This happens for all type parameters which are at + // index where index < n. + // Therefore we need to following check to fix the parent by setting the parent to the node which represents + // Map<String, Function<Long,$>> when we are invoking endVisit. + if(this.result && astNode instanceof ParameterizedSingleTypeReference && + Stream.of(((ParameterizedSingleTypeReference) astNode).typeArguments).anyMatch(n -> n == this.searchedNode)) { + this.parent = astNode; + } } private boolean visit(ASTNode astNode) { if(astNode == this.searchedNode) { |