From d90857f9aad97606ef17cfca3c953ca6df9f42f2 Mon Sep 17 00:00:00 2001 From: Snjezana Peco Date: Mon, 11 Jun 2018 17:10:47 +0200 Subject: [PATCH] interface/class snippets should not be available inside method bodies Signed-off-by: Snjezana Peco --- .../CompletionProposalRequestor.java | 6 + .../SnippetCompletionProposal.java | 168 +++++++++++++++-- .../internal/handlers/CompletionHandler.java | 2 +- .../preferences/CodeGenerationTemplate.java | 33 +++- .../handlers/CompletionHandlerTest.java | 174 +++++++++++++++++- 5 files changed, 360 insertions(+), 23 deletions(-) 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 3834aea5f5..fb8f8a9d7a 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 @@ -44,6 +44,7 @@ public final class CompletionProposalRequestor extends CompletionRequestor { private CompletionProposalDescriptionProvider descriptionProvider; private CompletionResponse response; private boolean fIsTestCodeExcluded; + private CompletionContext context; // Update SUPPORTED_KINDS when mapKind changes // @formatter:off @@ -130,6 +131,7 @@ public CompletionItem toCompletionItem(CompletionProposal proposal, int index) { @Override public void acceptContext(CompletionContext context) { super.acceptContext(context); + this.context = context; response.setContext(context); this.descriptionProvider = new CompletionProposalDescriptionProvider(context); } @@ -218,4 +220,8 @@ public boolean isTestCodeExcluded() { return fIsTestCodeExcluded; } + public CompletionContext getContext() { + return context; + } + } \ No newline at end of file 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 6bd8b5a067..3401436570 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 @@ -18,10 +18,26 @@ import java.util.Set; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.CompletionContext; import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.compiler.ITerminalSymbols; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.Initializer; +import org.eclipse.jdt.core.manipulation.CoreASTProvider; +import org.eclipse.jdt.internal.codeassist.InternalCompletionContext; +import org.eclipse.jdt.internal.codeassist.complete.CompletionOnFieldType; +import org.eclipse.jdt.internal.codeassist.complete.CompletionOnKeyword2; +import org.eclipse.jdt.internal.codeassist.complete.CompletionOnSingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.corext.dom.TokenScanner; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.corext.codemanipulation.StubUtility; +import org.eclipse.jdt.ls.core.internal.corext.refactoring.structure.ASTNodeSearchUtil; import org.eclipse.jdt.ls.core.internal.handlers.CompletionResolveHandler; import org.eclipse.jdt.ls.core.internal.preferences.CodeGenerationTemplate; import org.eclipse.lsp4j.CompletionItem; @@ -33,36 +49,156 @@ public class SnippetCompletionProposal { private static final String CLASS_SNIPPET_LABEL = "class"; private static final String INTERFACE_SNIPPET_LABEL = "interface"; + private static final String CLASS_KEYWORD = "class"; + private static final String INTERFACE_KEYWORD = "interface"; private static final Set UNSUPPORTED_RESOURCES = Sets.newHashSet("module-info.java", "package-info.java"); - public static List getSnippets(ICompilationUnit cu) { + public static List getSnippets(ICompilationUnit cu, CompletionContext completionContext, IProgressMonitor monitor) { if (cu == null) { throw new IllegalArgumentException("Compilation unit must not be null"); //$NON-NLS-1$ } + char[] completionToken = completionContext.getToken(); + boolean isInterfacePrefix = true; + boolean isClassPrefix = true; + if (completionToken != null && completionToken.length > 0) { + String prefix = new String(completionToken); + isInterfacePrefix = INTERFACE_KEYWORD.startsWith(prefix); + isClassPrefix = CLASS_KEYWORD.startsWith(prefix); + } + if (!isInterfacePrefix && !isClassPrefix) { + return Collections.emptyList(); + } + if (monitor == null) { + monitor = new NullProgressMonitor(); + } //This check might need to be pushed back to the different get*Snippet() methods, depending on future features if (UNSUPPORTED_RESOURCES.contains(cu.getResource().getName())) { return Collections.emptyList(); } + boolean needsPublic = needsPublic(cu, completionContext, monitor); + if (monitor.isCanceled()) { + return Collections.emptyList(); + } List res = new ArrayList<>(2); - CompletionItem classSnippet = getClassSnippet(cu); - if (classSnippet != null) { - res.add(classSnippet); + if (isClassPrefix) { + CompletionItem classSnippet = getClassSnippet(cu, completionContext, needsPublic, monitor); + if (classSnippet != null) { + res.add(classSnippet); + } } - CompletionItem interfaceSnippet = getInterfaceSnippet(cu); - if (interfaceSnippet != null) { - res.add(interfaceSnippet); + if (isInterfacePrefix) { + CompletionItem interfaceSnippet = getInterfaceSnippet(cu, completionContext, needsPublic, monitor); + if (interfaceSnippet != null) { + res.add(interfaceSnippet); + } } return res; } - private static CompletionItem getClassSnippet(ICompilationUnit cu) { + private static boolean accept(ICompilationUnit cu, CompletionContext completionContext, boolean acceptClass) { + if (completionContext != null && completionContext.isExtended()) { + if (completionContext.isInJavadoc()) { + return false; + } + if (completionContext instanceof InternalCompletionContext) { + InternalCompletionContext internalCompletionContext = (InternalCompletionContext) completionContext; + ASTNode node = internalCompletionContext.getCompletionNode(); + if (node instanceof CompletionOnKeyword2) { + return true; + } + if (node instanceof CompletionOnFieldType) { + return true; + } + if (acceptClass && node instanceof CompletionOnSingleNameReference) { + if (completionContext.getEnclosingElement() instanceof IMethod) { + CompilationUnit ast = CoreASTProvider.getInstance().getAST(cu, CoreASTProvider.WAIT_YES, null); + org.eclipse.jdt.core.dom.ASTNode astNode = ASTNodeSearchUtil.getAstNode(ast, completionContext.getTokenStart(), completionContext.getTokenEnd() - completionContext.getTokenStart() + 1); + return (astNode == null || (astNode.getParent() instanceof ExpressionStatement)); + } + return true; + } + } + } + return false; + } + + private static boolean needsPublic(ICompilationUnit cu, CompletionContext completionContext, IProgressMonitor monitor) { + if (completionContext != null && completionContext.isExtended()) { + if (completionContext.isInJavadoc()) { + return false; + } + if (completionContext instanceof InternalCompletionContext) { + InternalCompletionContext internalCompletionContext = (InternalCompletionContext) completionContext; + ASTNode node = internalCompletionContext.getCompletionNode(); + if (node instanceof CompletionOnKeyword2 || node instanceof CompletionOnFieldType || node instanceof CompletionOnSingleNameReference) { + if (completionContext.getEnclosingElement() instanceof IMethod) { + return false; + } + try { + TokenScanner scanner = new TokenScanner(cu); + int curr = scanner.readNext(0, true); + int previous = curr; + while (scanner.getCurrentEndOffset() < completionContext.getTokenStart()) { + previous = curr; + if (monitor.isCanceled()) { + return false; + } + if (curr == ITerminalSymbols.TokenNameEOF) { + break; + } + try { + curr = scanner.readNext(true); + } catch (CoreException e) { + // ignore + } + } + if (scanner.isModifier(previous)) { + return false; + } + } catch (CoreException e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + } + if (node instanceof CompletionOnSingleNameReference) { + CompilationUnit ast = CoreASTProvider.getInstance().getAST(cu, CoreASTProvider.WAIT_YES, null); + if (monitor.isCanceled()) { + return false; + } + org.eclipse.jdt.core.dom.ASTNode astNode = ASTNodeSearchUtil.getAstNode(ast, completionContext.getOffset(), 1); + if (astNode == null) { + return false; + } + while (astNode != null) { + if (astNode instanceof Initializer) { + return false; + } + astNode = astNode.getParent(); + } + } + return true; + } + } + } + return false; + } + + private static CompletionItem getClassSnippet(ICompilationUnit cu, CompletionContext completionContext, boolean needsPublic, IProgressMonitor monitor) { + if (!accept(cu, completionContext, true)) { + return null; + } + if (monitor.isCanceled()) { + return null; + } final CompletionItem classSnippetItem = new CompletionItem(); classSnippetItem.setLabel(CLASS_SNIPPET_LABEL); classSnippetItem.setFilterText(CLASS_SNIPPET_LABEL); classSnippetItem.setSortText(SortTextHelper.convertRelevance(1)); try { - classSnippetItem.setInsertText(StubUtility.getSnippetContent(cu, CodeGenerationTemplate.CLASSSNIPPET, cu.findRecommendedLineSeparator(), isSnippetStringSupported())); + if (needsPublic) { + classSnippetItem.setInsertText(StubUtility.getSnippetContent(cu, CodeGenerationTemplate.CLASSSNIPPET_PUBLIC, cu.findRecommendedLineSeparator(), isSnippetStringSupported())); + } else { + classSnippetItem.setInsertText(StubUtility.getSnippetContent(cu, CodeGenerationTemplate.CLASSSNIPPET_DEFAULT, cu.findRecommendedLineSeparator(), isSnippetStringSupported())); + } setFields(classSnippetItem, cu); } catch (CoreException e) { JavaLanguageServerPlugin.log(e.getStatus()); @@ -71,14 +207,24 @@ private static CompletionItem getClassSnippet(ICompilationUnit cu) { return classSnippetItem; } - private static CompletionItem getInterfaceSnippet(ICompilationUnit cu) { + private static CompletionItem getInterfaceSnippet(ICompilationUnit cu, CompletionContext completionContext, boolean needsPublic, IProgressMonitor monitor) { + if (!accept(cu, completionContext, false)) { + return null; + } + if (monitor.isCanceled()) { + return null; + } final CompletionItem interfaceSnippetItem = new CompletionItem(); interfaceSnippetItem.setFilterText(INTERFACE_SNIPPET_LABEL); interfaceSnippetItem.setLabel(INTERFACE_SNIPPET_LABEL); interfaceSnippetItem.setSortText(SortTextHelper.convertRelevance(0)); try { - interfaceSnippetItem.setInsertText(StubUtility.getSnippetContent(cu, CodeGenerationTemplate.INTERFACESNIPPET, cu.findRecommendedLineSeparator(), isSnippetStringSupported())); + if (needsPublic) { + interfaceSnippetItem.setInsertText(StubUtility.getSnippetContent(cu, CodeGenerationTemplate.INTERFACESNIPPET_PUBLIC, cu.findRecommendedLineSeparator(), isSnippetStringSupported())); + } else { + interfaceSnippetItem.setInsertText(StubUtility.getSnippetContent(cu, CodeGenerationTemplate.INTERFACESNIPPET_DEFAULT, cu.findRecommendedLineSeparator(), isSnippetStringSupported())); + } setFields(interfaceSnippetItem, cu); } catch (CoreException e) { JavaLanguageServerPlugin.log(e.getStatus()); 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 e5112f5637..abede72f20 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 @@ -41,7 +41,6 @@ Either, CompletionList> completion(CompletionParams positio completionItems = this.computeContentAssist(unit, position.getPosition().getLine(), position.getPosition().getCharacter(), monitor); - completionItems.addAll(SnippetCompletionProposal.getSnippets(unit)); } catch (OperationCanceledException ignorable) { // No need to pollute logs when query is cancelled monitor.setCanceled(true); @@ -109,6 +108,7 @@ public boolean isCanceled() { try { unit.codeComplete(offset, collector, subMonitor); proposals.addAll(collector.getCompletionItems()); + proposals.addAll(SnippetCompletionProposal.getSnippets(unit, collector.getContext(), subMonitor)); } catch (OperationCanceledException e) { monitor.setCanceled(true); } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/CodeGenerationTemplate.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/CodeGenerationTemplate.java index 85ab660bf0..763bca3f31 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/CodeGenerationTemplate.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/CodeGenerationTemplate.java @@ -109,23 +109,38 @@ public enum CodeGenerationTemplate { CodeTemplateContextType.METHODBODY_CONTEXTTYPE, CodeTemplatePreferences.CODETEMPLATE_METHODBODY_DEFAULT), + /** + * Snippet `public class` content template + */ + CLASSSNIPPET_PUBLIC( + CodeTemplatePreferences.CODETEMPLATE_CODESNIPPET, + CodeTemplateContextType.CLASSSNIPPET_CONTEXTTYPE, + CodeTemplatePreferences.CODETEMPLATE_CLASSSNIPPET_PUBLIC), + /** * Snippet `class` content template */ - CLASSSNIPPET( + CLASSSNIPPET_DEFAULT( CodeTemplatePreferences.CODETEMPLATE_CODESNIPPET, CodeTemplateContextType.CLASSSNIPPET_CONTEXTTYPE, CodeTemplatePreferences.CODETEMPLATE_CLASSSNIPPET_DEFAULT), + /** + * Snippet `public interface` content template + */ + INTERFACESNIPPET_PUBLIC( + CodeTemplatePreferences.CODETEMPLATE_CODESNIPPET, + CodeTemplateContextType.INTERFACESNIPPET_CONTEXTTYPE, + CodeTemplatePreferences.CODETEMPLATE_INTERFACESNIPPET_PUBLIC), + /** * Snippet `interface` content template */ - INTERFACESNIPPET( + INTERFACESNIPPET_DEFAULT( CodeTemplatePreferences.CODETEMPLATE_CODESNIPPET, CodeTemplateContextType.INTERFACESNIPPET_CONTEXTTYPE, CodeTemplatePreferences.CODETEMPLATE_INTERFACESNIPPET_DEFAULT); - private final String preferenceId; private final String contextType; private final String defaultContent; @@ -288,10 +303,18 @@ class CodeTemplatePreferences { /** * Default value for class snippet body content */ - public static final String CODETEMPLATE_CLASSSNIPPET_DEFAULT = "${package_header}/**\n * ${type_name}\n */\npublic class ${type_name} {\n\n\t${cursor}\n}"; + public static final String CODETEMPLATE_CLASSSNIPPET_DEFAULT = "${package_header}class ${type_name} {\n\n\t${cursor}\n}"; + /** + * Default value for public class snippet body content + */ + public static final String CODETEMPLATE_CLASSSNIPPET_PUBLIC = "${package_header}/**\n * ${type_name}\n */\npublic class ${type_name} {\n\n\t${cursor}\n}"; /** * Default value for interface snippet body content */ - public static final String CODETEMPLATE_INTERFACESNIPPET_DEFAULT = "${package_header}/**\n * ${type_name}\n */\npublic interface ${type_name} {\n\n\t${cursor}\n}"; + public static final String CODETEMPLATE_INTERFACESNIPPET_DEFAULT = "${package_header}interface ${type_name} {\n\n\t${cursor}\n}"; + /** + * Default value for public interface snippet body content + */ + public static final String CODETEMPLATE_INTERFACESNIPPET_PUBLIC = "${package_header}/**\n * ${type_name}\n */\npublic interface ${type_name} {\n\n\t${cursor}\n}"; } 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 a71f2c9900..193c25e27c 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 @@ -296,7 +296,7 @@ public void testCompletion_import_package() throws JavaModelException{ CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); assertNotNull(list); - assertEquals(3, list.getItems().size()); + assertEquals(1, list.getItems().size()); CompletionItem item = list.getItems().get(0); // Check completion item assertNull(item.getInsertText()); @@ -334,7 +334,7 @@ public void testCompletion_import_static() throws JavaModelException{ CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); assertNotNull(list); - assertEquals(11, list.getItems().size()); + assertEquals(9, list.getItems().size()); //// .SECONDS - enum value CompletionItem secondsFieldItem = list.getItems().get(0); @@ -479,7 +479,7 @@ public void testCompletion_field() throws JavaModelException{ CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); assertNotNull(list); - assertEquals(3, list.getItems().size()); + assertEquals(1, list.getItems().size()); CompletionItem item = list.getItems().get(0); assertEquals(CompletionItemKind.Field, item.getKind()); assertEquals("myTestString", item.getInsertText()); @@ -508,7 +508,7 @@ public void testCompletion_import_type() throws JavaModelException{ CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); assertNotNull(list); - assertEquals(3, list.getItems().size()); + assertEquals(1, list.getItems().size()); CompletionItem item = list.getItems().get(0); assertEquals(CompletionItemKind.Class, item.getKind()); assertEquals("Map", item.getInsertText()); @@ -1429,7 +1429,7 @@ public void testCompletion_testClassesDontLeakIntoMainCode() throws Exception { //@formatter:on int[] loc = findCompletionLocation(unit, " AbstractTe"); CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); - assertEquals("Test proposals leaked:\n" + list.getItems(), 2, list.getItems().size()); + assertEquals("Test proposals leaked:\n" + list.getItems(), 0, list.getItems().size()); } @Test @@ -1488,7 +1488,7 @@ public void testCompletion_testClassesAvailableIntoTestCode() throws Exception { int[] loc = findCompletionLocation(unit, " AbstractTe"); CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); assertNotNull(list); - assertEquals("Test proposals missing from :\n" + list, 3, list.getItems().size()); + assertEquals("Test proposals missing from :\n" + list, 1, list.getItems().size()); assertEquals("AbstractTest - foo.bar", list.getItems().get(0).getLabel()); } @@ -1585,6 +1585,168 @@ private ICompilationUnit getCompletionOverwriteReplaceUnit() throws JavaModelExc return unit; } + @Test + public void testSnippet_with_public() throws JavaModelException { + ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", + //@formatter:off + "package org.sample;\n" + + "public "); + //@formatter:off + int[] loc = findCompletionLocation(unit, "public "); + CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + CompletionItem ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("class") + && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNotNull(ci); + String text = ci.getInsertText(); + assertEquals("class Test {\n\n\t${0}\n}", text); + ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("interface") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNotNull(ci); + text = ci.getInsertText(); + assertEquals("interface Test {\n\n\t${0}\n}", text); + } + + @Test + public void testSnippet_context_javadoc() throws JavaModelException { + ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", + //@formatter:off + "package org.sample;\n" + + "/**\n */"); + //@formatter:off + int[] loc = findCompletionLocation(unit, "/**"); + CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + CompletionItem ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("class") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("interface") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + } + + @Test + public void testSnippet_context_package() throws JavaModelException { + ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", + //@formatter:off + "package org.sample;\n"); + //@formatter:off + int[] loc = findCompletionLocation(unit, "package "); + CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + CompletionItem ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("class") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("interface") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + } + + @Test + public void testSnippet_context_method1() throws JavaModelException { + ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", + //@formatter:off + "package org.sample;\n" + + "public class Test {\n\n" + + " void test() {\n\n" + + " }\n" + + "}\n"); + //@formatter:off + int[] loc = findCompletionLocation(unit, "{\n\n"); + CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + CompletionItem ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("class") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNotNull(ci); + String text = ci.getInsertText(); + assertEquals("class ${1:InnerTest} {\n\n\t${0}\n}", text); + ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("interface") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + } + + @Test + public void testSnippet_context_method2() throws JavaModelException { + ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", + //@formatter:off + "package org.sample;\n" + + "public class Test {\n\n" + + " void test() {\n\n" + + " if (c\n" + + " }\n" + + "}\n"); + //@formatter:off + int[] loc = findCompletionLocation(unit, "if (c"); + CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + CompletionItem ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("class") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("interface") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + } + + @Test + public void testSnippet_context_method3() throws JavaModelException { + ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", + //@formatter:off + "package org.sample;\n" + + "public class Test {\n\n" + + " void test() {\n\n" + + " int \n" + + " }\n" + + "}\n"); + //@formatter:off + int[] loc = findCompletionLocation(unit, "int "); + CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + CompletionItem ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("class") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("interface") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + } + + @Test + public void testSnippet_context_static() throws JavaModelException { + ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", + //@formatter:off + "package org.sample;\n" + + "public class Test {\n\n" + + " static {\n" + + " }\n" + + "}\n"); + //@formatter:off + int[] loc = findCompletionLocation(unit, "static {\n"); + CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + CompletionItem ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("class") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNotNull(ci); + String text = ci.getInsertText(); + assertEquals("class ${1:InnerTest} {\n\n\t${0}\n}", text); + ci = list.getItems().stream() + .filter( item-> (item.getLabel().matches("interface") && item.getKind() == CompletionItemKind.Snippet)) + .findFirst().orElse(null); + assertNull(ci); + } + @Test public void testStaticImports1() throws Exception { List favorites = new ArrayList<>();