diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/CompletionProposalRequestor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/CompletionProposalRequestor.java index 9fd8a09179..aafe7269de 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/CompletionProposalRequestor.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/CompletionProposalRequestor.java @@ -280,7 +280,7 @@ public List getCompletionItems(IProgressMonitor monitor) { response.setProposals(proposals); } response.setItems(completionItems); - response.setUri(this.uri); + response.setCommonData(CompletionResolveHandler.DATA_FIELD_URI, uri); CompletionResponses.store(response); return completionItems; diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/SnippetCompletionProposal.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/SnippetCompletionProposal.java index a9456d9df4..4e5dd59c6c 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/SnippetCompletionProposal.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/SnippetCompletionProposal.java @@ -357,7 +357,7 @@ private static List getGenericSnippets(SnippetCompletionContext response.setProposals(proposals); response.setItems(res); - response.setUri(uri); + response.setCommonData(CompletionResolveHandler.DATA_FIELD_URI, uri); CompletionResponses.store(response); return res; } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/template/java/PostfixTemplateEngine.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/template/java/PostfixTemplateEngine.java index aa3591423c..f742575dbd 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/template/java/PostfixTemplateEngine.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/template/java/PostfixTemplateEngine.java @@ -145,7 +145,7 @@ public List complete(IDocument document, int offset, ICompilatio response.setProposals(proposals); response.setItems(res); - response.setUri(JDTUtils.toURI(compilationUnit)); + response.setCommonData(CompletionResolveHandler.DATA_FIELD_URI, JDTUtils.toURI(compilationUnit)); CompletionResponses.store(response); return res; } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandler.java index d59c7bc5c8..4ecdb49401 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandler.java @@ -18,6 +18,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.apache.commons.lang3.StringUtils; @@ -121,6 +122,7 @@ public Either, CompletionList> completion(CompletionParams JavaLanguageServerPlugin.logInfo("Completion request completed"); } long executionTime = System.currentTimeMillis() - startTime; + String lastRequestId = null; for (CompletionItem item : $.getItems()) { String requestId = ""; String proposalId = ""; @@ -128,12 +130,27 @@ public Either, CompletionList> completion(CompletionParams if (data != null) { requestId = data.getOrDefault(CompletionResolveHandler.DATA_FIELD_REQUEST_ID, ""); proposalId = data.getOrDefault(CompletionResolveHandler.DATA_FIELD_PROPOSAL_ID, ""); - data.put(CompletionRanking.COMPLETION_EXECUTION_TIME, String.valueOf(executionTime)); + } + if (requestId.isEmpty() || proposalId.isEmpty()) { + continue; } item.setCommand(new Command("", "java.completion.onDidSelect", Arrays.asList( requestId, proposalId ))); + + if (Objects.equals(requestId, lastRequestId)) { + continue; + } + lastRequestId = requestId; + int pId = Integer.parseInt(proposalId); + long rId = Long.parseLong(requestId); + CompletionResponse completionResponse = CompletionResponses.get(rId); + if (completionResponse == null || completionResponse.getProposals().size() <= pId) { + JavaLanguageServerPlugin.logError("Failed to save common data for completion items."); + continue; + } + completionResponse.setCommonData(CompletionRanking.COMPLETION_EXECUTION_TIME, String.valueOf(executionTime)); } return Either.forRight($); } @@ -155,6 +172,12 @@ public void onDidCompletionItemSelect(String requestId, String proposalId) throw throw ExceptionFactory.newException("Cannot get the completion item."); } + // get the cached completion execution time and set it to the selected item in case that providers need it. + String executionTime = completionResponse.getCommonData(CompletionRanking.COMPLETION_EXECUTION_TIME); + if (executionTime != null) { + ((Map)item.getData()).put(CompletionRanking.COMPLETION_EXECUTION_TIME, executionTime); + } + List providers = ((CompletionContributionService) JavaLanguageServerPlugin.getCompletionContributionService()).getRankingProviders(); for (ICompletionRankingProvider provider : providers) { diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResolveHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResolveHandler.java index d616dffbb1..371feea515 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResolveHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResolveHandler.java @@ -87,6 +87,7 @@ public CompletionResolveHandler(PreferenceManager manager) { this.manager = manager; } + public static final String DATA_FIELD_URI = "uri"; public static final String DATA_FIELD_DECLARATION_SIGNATURE = "decl_signature"; public static final String DATA_FIELD_SIGNATURE= "signature"; public static final String DATA_FIELD_NAME = "name"; @@ -111,7 +112,7 @@ public CompletionItem resolve(CompletionItem param, IProgressMonitor monitor) { throw new IllegalStateException("Invalid completion proposal"); } - String uri = completionResponse.getUri(); + String uri = completionResponse.getCommonData(DATA_FIELD_URI); ICompilationUnit unit = JDTUtils.resolveCompilationUnit(uri); if (unit == null) { throw new IllegalStateException(NLS.bind("Unable to match Compilation Unit from {0} ", uri)); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResponse.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResponse.java index c2584fc89b..2945fe7e81 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResponse.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResponse.java @@ -12,7 +12,9 @@ *******************************************************************************/ package org.eclipse.jdt.ls.core.internal.handlers; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import org.eclipse.jdt.core.CompletionContext; @@ -30,7 +32,10 @@ public class CompletionResponse { private Long id; private int offset; private CompletionContext context; - private String uri; + /** + * Stores the data that are common among the completion items. + */ + private Map commonData = new HashMap<>(); private List proposals; private List items; @@ -57,18 +62,15 @@ public CompletionContext getContext() { public void setContext(CompletionContext context) { this.context = context; } - /** - * the uri of the document. - */ - public String getUri() { - return uri; + + public String getCommonData(String key) { + return this.commonData.get(key); } - /** - * @param uri the document uri to set. - */ - public void setUri(String uri) { - this.uri = uri; + + public void setCommonData(String key, String value) { + this.commonData.put(key, value); } + /** * @return the proposals */ 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 6178b51b5c..9f5ffa1c45 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 @@ -46,6 +46,7 @@ import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.manipulation.CoreASTProvider; import org.eclipse.jdt.internal.codeassist.impl.AssistOptions; +import org.eclipse.jdt.ls.core.contentassist.CompletionRanking; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.JSONUtility; import org.eclipse.jdt.ls.core.internal.JavaClientConnection; @@ -287,11 +288,32 @@ public void testCompletion_dataFieldURI() throws Exception { long requestId = Long.parseLong(data.get(CompletionResolveHandler.DATA_FIELD_REQUEST_ID)); CompletionResponse completionResponse = CompletionResponses.get(requestId); assertNotNull(completionResponse); - String uri = completionResponse.getUri(); + String uri = completionResponse.getCommonData(CompletionResolveHandler.DATA_FIELD_URI); assertNotNull(uri); assertTrue("unexpected URI prefix: " + uri, uri.matches("file://.*/src/java/Foo\\.java")); } + @Test + public void testCompletion_dataFieldExecutionTime() throws Exception { + ICompilationUnit unit = getWorkingCopy( + "src/java/Foo.java", + "public class Foo {\n"+ + " void foo() {\n"+ + " Objec\n"+ + " }\n"+ + "}\n"); + CompletionList list = requestCompletions(unit, "Objec"); + assertNotNull(list); + assertFalse("No proposals were found",list.getItems().isEmpty()); + + Map data = (Map) list.getItems().get(0).getData(); + long requestId = Long.parseLong(data.get(CompletionResolveHandler.DATA_FIELD_REQUEST_ID)); + CompletionResponse completionResponse = CompletionResponses.get(requestId); + assertNotNull(completionResponse); + String time = completionResponse.getCommonData(CompletionRanking.COMPLETION_EXECUTION_TIME); + assertNotNull(time); + } + @Test public void testCompletion_constructor() throws Exception{ diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionRankingProviderTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionRankingProviderTest.java index ea9f81fbf5..6858cce411 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionRankingProviderTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionRankingProviderTest.java @@ -87,14 +87,15 @@ public void testRank() throws Exception { assertTrue(recommended.getLabel().startsWith("★")); assertTrue(((Map)recommended.getData()).containsKey("foo")); assertEquals(recommended.getFilterText(), recommended.getInsertText()); - assertTrue(((Map)recommended.getData()).containsKey(CompletionRanking.COMPLETION_EXECUTION_TIME)); } @Test public void testOnDidCompletionItemSelect() throws Exception { CompletionHandler handler = new CompletionHandler(JavaLanguageServerPlugin.getPreferencesManager()); CompletionResponse response = new CompletionResponse(); - response.setItems(Arrays.asList(new CompletionItem())); + CompletionItem completionItem = new CompletionItem(); + completionItem.setData(new HashMap<>()); + response.setItems(Arrays.asList(completionItem)); CompletionResponses.store(response); handler.onDidCompletionItemSelect(String.valueOf(response.getId()), "0");