From 7483ce9bf531fdff35bf0f4539071efec5d9174f Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Mon, 19 Sep 2022 21:13:22 +0200 Subject: [PATCH 1/2] Fix type completion when type name conflicts When type completion are applied where the same simple name already imported in the scope, the second type completion is completed as a fully qualified completion. --- ...CompletionProposalReplacementProvider.java | 10 ++++++- .../handlers/CompletionHandlerTest.java | 26 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/CompletionProposalReplacementProvider.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/CompletionProposalReplacementProvider.java index 7b45bbe179..d0928507d9 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/CompletionProposalReplacementProvider.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/CompletionProposalReplacementProvider.java @@ -37,10 +37,13 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.ASTRequestor; +import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; +import org.eclipse.jdt.core.manipulation.SharedASTProviderCore; import org.eclipse.jdt.internal.codeassist.CompletionEngine; +import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; import org.eclipse.jdt.internal.corext.dom.IASTSharedValues; import org.eclipse.jdt.internal.corext.template.java.SignatureUtil; import org.eclipse.jdt.ls.core.internal.ChangeUtil; @@ -1021,7 +1024,12 @@ private String computeJavaTypeReplacementString(CompletionProposal proposal) { /* Add imports if the preference is on. */ if (importRewrite != null) { - return importRewrite.addImport(qualifiedTypeName, null); + CompilationUnit cu = SharedASTProviderCore.getAST(compilationUnit, SharedASTProviderCore.WAIT_NO, new NullProgressMonitor()); + ContextSensitiveImportRewriteContext rewriteContext = null; + if (cu != null) { + rewriteContext = new ContextSensitiveImportRewriteContext(cu, this.offset, this.importRewrite); + } + return importRewrite.addImport(qualifiedTypeName, rewriteContext); } // fall back for the case we don't have an import rewrite (see diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java index a15da89047..3e70b39cbe 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java @@ -3499,6 +3499,32 @@ public void testCompletion_QualifiedName2() throws Exception { assertEquals("java.util.ArrayList()", list.getItems().get(0).getFilterText()); } + @Test + public void testCompletion_withConflictingTypeNames() throws Exception{ + getWorkingCopy("src/java/List.java", + "package util;\n" + + "public class List {\n" + + "}\n"); + ICompilationUnit unit = getWorkingCopy( + "src/java/Foo.java", + "package util;\n" + + "public class Foo {\n"+ + " void foo() {\n"+ + " Object list = new List();\n" + + " List \n"+ + " }\n"+ + "}\n"); + CompletionList list = requestCompletions(unit, "List"); + assertNotNull(list); + assertFalse("No proposals were found",list.getItems().isEmpty()); + + List items = list.getItems().stream().filter(p -> "java.util.List".equals(p.getDetail())) + .collect(Collectors.toList()); + assertFalse("java.util.List not found",items.isEmpty()); + assertEquals("java.util.List", items.get(0).getInsertText()); + } + + private CompletionList requestCompletions(ICompilationUnit unit, String completeBehind) throws JavaModelException { int[] loc = findCompletionLocation(unit, completeBehind); return server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); From f44997f9bf74f921f9ee118b8202e9aaa1df858a Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Tue, 20 Sep 2022 22:04:12 +0200 Subject: [PATCH 2/2] Fix unit tests --- .../AbstractCompilationUnitBasedTest.java | 11 ++++++++++- .../internal/handlers/CompletionHandlerTest.java | 15 +++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/AbstractCompilationUnitBasedTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/AbstractCompilationUnitBasedTest.java index 95ba31d3f6..abfccceb4e 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/AbstractCompilationUnitBasedTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/AbstractCompilationUnitBasedTest.java @@ -69,8 +69,17 @@ protected IFile getFile(String path) { } protected int[] findCompletionLocation(ICompilationUnit unit, String completeBehind) throws JavaModelException { + return findCompletionLocation(unit, completeBehind, 0); + } + + protected int[] findCompletionLocation(ICompilationUnit unit, String completeBehind, int fromIndex) throws JavaModelException { String str= unit.getSource(); - int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + int cursorLocation; + if (fromIndex > 0) { + cursorLocation = str.indexOf(completeBehind, fromIndex) + completeBehind.length(); + } else { + cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + } return JsonRpcHelpers.toLine(unit.getBuffer(), cursorLocation); } diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java index 3e70b39cbe..4cab41af6e 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java @@ -3501,7 +3501,7 @@ public void testCompletion_QualifiedName2() throws Exception { @Test public void testCompletion_withConflictingTypeNames() throws Exception{ - getWorkingCopy("src/java/List.java", + getWorkingCopy("src/java/List.java", "package util;\n" + "public class List {\n" + "}\n"); @@ -3514,19 +3514,26 @@ public void testCompletion_withConflictingTypeNames() throws Exception{ " List \n"+ " }\n"+ "}\n"); - CompletionList list = requestCompletions(unit, "List"); + CoreASTProvider.getInstance().setActiveJavaElement(unit); + CoreASTProvider.getInstance().getAST(unit, CoreASTProvider.WAIT_YES, monitor); + + CompletionList list = requestCompletions(unit, "List", unit.getSource().indexOf("List()") + 6); assertNotNull(list); assertFalse("No proposals were found",list.getItems().isEmpty()); List items = list.getItems().stream().filter(p -> "java.util.List".equals(p.getDetail())) .collect(Collectors.toList()); assertFalse("java.util.List not found",items.isEmpty()); - assertEquals("java.util.List", items.get(0).getInsertText()); + assertEquals("java.util.List", items.get(0).getTextEdit().getLeft().getNewText()); } private CompletionList requestCompletions(ICompilationUnit unit, String completeBehind) throws JavaModelException { - int[] loc = findCompletionLocation(unit, completeBehind); + return requestCompletions(unit, completeBehind, 0); + } + + private CompletionList requestCompletions(ICompilationUnit unit, String completeBehind, int fromIndex) throws JavaModelException { + int[] loc = findCompletionLocation(unit, completeBehind, fromIndex); return server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); }