diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/TypeProposalUtils.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/TypeProposalUtils.java index c6ffb22531..9b13d87a05 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/TypeProposalUtils.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/TypeProposalUtils.java @@ -28,6 +28,7 @@ import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.jdt.internal.corext.template.java.SignatureUtil; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.preferences.Preferences; /** * Method implementations extracted from JDT UI. Mostly from @@ -41,7 +42,6 @@ public class TypeProposalUtils { private static final String PACKAGE_INFO_JAVA = "package-info.java"; //$NON-NLS-1$ - private static final int IMPORTS_THRESHOLD = 99; static void createName(ITypeBinding type, boolean includePackage, List list) { @@ -163,10 +163,10 @@ static boolean isPackageInfo(ICompilationUnit cu) { static ImportRewrite createImportRewrite(ICompilationUnit compilationUnit) { try { ImportRewrite rewrite = ImportRewrite.create(compilationUnit, true); - String[] importOrder = JavaLanguageServerPlugin.getPreferencesManager() == null ? new String[0] : JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getImportOrder(); - rewrite.setImportOrder(importOrder); - rewrite.setOnDemandImportThreshold(IMPORTS_THRESHOLD); - rewrite.setStaticOnDemandImportThreshold(IMPORTS_THRESHOLD); + Preferences preferences = JavaLanguageServerPlugin.getPreferencesManager() == null ? new Preferences() : JavaLanguageServerPlugin.getPreferencesManager().getPreferences(); + rewrite.setImportOrder(preferences.getImportOrder()); + rewrite.setOnDemandImportThreshold(preferences.getImportOnDemandThreshold()); + rewrite.setStaticOnDemandImportThreshold(preferences.getStaticImportOnDemandThreshold()); return rewrite; } catch (JavaModelException e) { JavaLanguageServerPlugin.logException(e.getMessage(), e); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/PreferenceManager.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/PreferenceManager.java index 489a0db462..7aac9d918f 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/PreferenceManager.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/PreferenceManager.java @@ -18,13 +18,9 @@ import java.util.Arrays; import java.util.Hashtable; import java.util.Map; -import java.util.Objects; import java.util.stream.Collectors; import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.IWorkspaceDescription; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.ListenerList; @@ -93,8 +89,6 @@ public static void initialize() { IEclipsePreferences defEclipsePrefs = DefaultScope.INSTANCE.getNode(IConstants.PLUGIN_ID); defEclipsePrefs.put("org.eclipse.jdt.ui.typefilter.enabled", ""); defEclipsePrefs.put(CodeStyleConfiguration.ORGIMPORTS_IMPORTORDER, String.join(";", Preferences.JAVA_IMPORT_ORDER_DEFAULT)); - defEclipsePrefs.put(CodeStyleConfiguration.ORGIMPORTS_ONDEMANDTHRESHOLD, "99"); - defEclipsePrefs.put(CodeStyleConfiguration.ORGIMPORTS_STATIC_ONDEMANDTHRESHOLD, "99"); defEclipsePrefs.put(MembersOrderPreferenceCacheCommon.APPEARANCE_MEMBER_SORT_ORDER, "T,SF,SI,SM,F,I,C,M"); //$NON-NLS-1$ defEclipsePrefs.put(StubUtility.CODEGEN_KEYWORD_THIS, Boolean.FALSE.toString()); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java index 6bac113b92..e5b0fb4522 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java @@ -32,6 +32,7 @@ import org.eclipse.core.internal.resources.PreferenceInitializer; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jdt.core.manipulation.CodeStyleConfiguration; @@ -263,6 +264,30 @@ public class Preferences { */ public static final String MEMBER_SORT_ORDER = "java.memberSortOrder"; //$NON-NLS-1$ + /** + * A named preference that specifies the number of imports added before a + * star-import declaration is used. + *

+ * Value is of type Integer: positive value specifying the number + * of non star-import is used + *

+ */ + public static final String IMPORTS_ONDEMANDTHRESHOLD = "java.sources.organizeImports.starThreshold"; //$NON-NLS-1$ + + /** + * A named preference that specifies the number of static imports added before a + * star-import declaration is used. + *

+ * Value is of type Integer: positive value specifying the number + * of non star-import is used + *

+ */ + public static final String IMPORTS_STATIC_ONDEMANDTHRESHOLD = "java.sources.organizeImports.staticStarThreshold"; //$NON-NLS-1$ + + public static final int IMPORTS_ONDEMANDTHRESHOLD_DEFAULT = 99; + + public static final int IMPORTS_STATIC_ONDEMANDTHRESHOLD_DEFAULT = 99; + /** * Preference key for the id(s) of the preferred content provider(s). */ @@ -399,6 +424,8 @@ public class Preferences { private Collection triggerFiles; private int parallelBuildsCount; private int maxCompletionResults; + private int importOnDemandThreshold; + private int staticImportOnDemandThreshold; private Set runtimes = new HashSet<>(); static { @@ -565,6 +592,8 @@ public Preferences() { filteredTypes = JAVA_COMPLETION_FILTERED_TYPES_DEFAULT; parallelBuildsCount = PreferenceInitializer.PREF_MAX_CONCURRENT_BUILDS_DEFAULT; maxCompletionResults = JAVA_COMPLETION_MAX_RESULTS_DEFAULT; + importOnDemandThreshold = IMPORTS_ONDEMANDTHRESHOLD_DEFAULT; + staticImportOnDemandThreshold = IMPORTS_STATIC_ONDEMANDTHRESHOLD_DEFAULT; referencedLibraries = JAVA_PROJECT_REFERENCED_LIBRARIES_DEFAULT; } @@ -736,6 +765,12 @@ public static Preferences createFrom(Map configuration) { int maxCompletions = getInt(configuration, JAVA_COMPLETION_MAX_RESULTS_KEY, JAVA_COMPLETION_MAX_RESULTS_DEFAULT); prefs.setMaxCompletionResults(maxCompletions); + int onDemandThreshold = getInt(configuration, IMPORTS_ONDEMANDTHRESHOLD, IMPORTS_ONDEMANDTHRESHOLD_DEFAULT); + prefs.setImportOnDemandThreshold(onDemandThreshold); + + int staticOnDemandThreshold = getInt(configuration, IMPORTS_STATIC_ONDEMANDTHRESHOLD, IMPORTS_STATIC_ONDEMANDTHRESHOLD_DEFAULT); + prefs.setStaticImportOnDemandThreshold(staticOnDemandThreshold); + List runtimeList = getList(configuration, JAVA_CONFIGURATION_RUNTIMES, JAVA_IMPORT_ORDER_DEFAULT); Set runtimes = new HashSet<>(); boolean[] hasDefault = { false }; @@ -1302,4 +1337,34 @@ public Preferences setRuntimes(Set runtimes) { this.runtimes = runtimes; return this; } + + public int getImportOnDemandThreshold() { + return importOnDemandThreshold; + } + + public Preferences setImportOnDemandThreshold(int importOnDemandThreshold) { + if (importOnDemandThreshold < 0) { + this.importOnDemandThreshold = IMPORTS_ONDEMANDTHRESHOLD_DEFAULT; + } else { + this.importOnDemandThreshold = importOnDemandThreshold; + } + IEclipsePreferences defEclipsePrefs = DefaultScope.INSTANCE.getNode(IConstants.PLUGIN_ID); + defEclipsePrefs.put(CodeStyleConfiguration.ORGIMPORTS_ONDEMANDTHRESHOLD, String.valueOf(this.importOnDemandThreshold)); + return this; + } + + public int getStaticImportOnDemandThreshold() { + return staticImportOnDemandThreshold; + } + + public Preferences setStaticImportOnDemandThreshold(int staticImportOnDemandThreshold) { + if (staticImportOnDemandThreshold < 0) { + this.staticImportOnDemandThreshold = IMPORTS_STATIC_ONDEMANDTHRESHOLD_DEFAULT; + } else { + this.staticImportOnDemandThreshold = staticImportOnDemandThreshold; + } + IEclipsePreferences defEclipsePrefs = DefaultScope.INSTANCE.getNode(IConstants.PLUGIN_ID); + defEclipsePrefs.put(CodeStyleConfiguration.ORGIMPORTS_STATIC_ONDEMANDTHRESHOLD, String.valueOf(this.staticImportOnDemandThreshold)); + return this; + } } diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/OrganizeImportsCommandTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/OrganizeImportsCommandTest.java index 3c7ee445a4..d48d3ca7b0 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/OrganizeImportsCommandTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/commands/OrganizeImportsCommandTest.java @@ -397,6 +397,86 @@ public void testOrganizeImportsInProject() throws CoreException, BadLocationExce assertEquals(buf.toString(), getOrganizeImportResult(cu2, rootEdit)); } + @Test + public void testOrganizeImportsOnDemandThreshold() throws Exception { + int onDemandTreshold = preferenceManager.getPreferences().getImportOnDemandThreshold(); + try { + preferenceManager.getPreferences().setImportOnDemandThreshold(2); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + StringBuilder buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.HashMap;\n"); + buf.append("import java.util.ArrayList;\n"); + buf.append("\n"); + buf.append("public class E {\n"); + buf.append("\n"); + buf.append(" public E() {\n"); + buf.append(" ArrayList list = new ArrayList();\n"); + buf.append(" HashMap map = new HashMap();\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu = pack1.createCompilationUnit("E.java", buf.toString(), false, null); + buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.*;\n"); + buf.append("\n"); + buf.append("public class E {\n"); + buf.append("\n"); + buf.append(" public E() {\n"); + buf.append(" ArrayList list = new ArrayList();\n"); + buf.append(" HashMap map = new HashMap();\n"); + buf.append(" }\n"); + buf.append("}\n"); + WorkspaceEdit rootEdit = new WorkspaceEdit(); + command.organizeImportsInCompilationUnit(cu, rootEdit); + assertEquals(buf.toString(), getOrganizeImportResult(cu, rootEdit)); + } finally { + preferenceManager.getPreferences().setImportOnDemandThreshold(onDemandTreshold); + } + } + + @Test + public void testOrganizeImportsStaticOnDemandThreshold() throws Exception { + int staticOnDemandTreshold = preferenceManager.getPreferences().getStaticImportOnDemandThreshold(); + try { + preferenceManager.getPreferences().setStaticImportOnDemandThreshold(2); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + StringBuilder buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import static java.lang.Math.pow;\n"); + buf.append("import static java.lang.Math.sqrt;\n"); + buf.append("\n"); + buf.append("public class E {\n"); + buf.append("\n"); + buf.append(" public E() {\n"); + buf.append(" double d1 = sqrt(4);\n"); + buf.append(" double d2 = pow(2, 2);\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu = pack1.createCompilationUnit("E.java", buf.toString(), false, null); + buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import static java.lang.Math.*;\n"); + buf.append("\n"); + buf.append("public class E {\n"); + buf.append("\n"); + buf.append(" public E() {\n"); + buf.append(" double d1 = sqrt(4);\n"); + buf.append(" double d2 = pow(2, 2);\n"); + buf.append(" }\n"); + buf.append("}\n"); + WorkspaceEdit rootEdit = new WorkspaceEdit(); + command.organizeImportsInCompilationUnit(cu, rootEdit); + assertEquals(buf.toString(), getOrganizeImportResult(cu, rootEdit)); + } finally { + preferenceManager.getPreferences().setStaticImportOnDemandThreshold(staticOnDemandTreshold); + } + } + private String getOrganizeImportResult(ICompilationUnit cu, WorkspaceEdit we) throws BadLocationException, CoreException { List change = we.getChanges().get(JDTUtils.toURI(cu)); if (change == null) { diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/OrganizeImportsActionTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/OrganizeImportsActionTest.java index 259094182b..f6c833de14 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/OrganizeImportsActionTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/OrganizeImportsActionTest.java @@ -150,6 +150,84 @@ public void testOrganizeImportsSort() throws Exception { assertCodeActions(cu, e1); } + @Test + public void testOrganizeImportsOnDemandThreshold() throws Exception { + int onDemandTreshold = preferenceManager.getPreferences().getImportOnDemandThreshold(); + try { + preferenceManager.getPreferences().setImportOnDemandThreshold(2); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + StringBuilder buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.HashMap;\n"); + buf.append("import java.util.ArrayList;\n"); + buf.append("\n"); + buf.append("public class E {\n"); + buf.append("\n"); + buf.append(" public E() {\n"); + buf.append(" ArrayList list = new ArrayList();\n"); + buf.append(" HashMap map = new HashMap();\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu = pack1.createCompilationUnit("E.java", buf.toString(), false, null); + buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.*;\n"); + buf.append("\n"); + buf.append("public class E {\n"); + buf.append("\n"); + buf.append(" public E() {\n"); + buf.append(" ArrayList list = new ArrayList();\n"); + buf.append(" HashMap map = new HashMap();\n"); + buf.append(" }\n"); + buf.append("}\n"); + Expected e1 = new Expected("Organize imports", buf.toString()); + assertCodeActions(cu, e1); + } finally { + preferenceManager.getPreferences().setImportOnDemandThreshold(onDemandTreshold); + } + } + + @Test + public void testOrganizeImportsStaticOnDemandThreshold() throws Exception { + int staticOnDemandTreshold = preferenceManager.getPreferences().getStaticImportOnDemandThreshold(); + try { + preferenceManager.getPreferences().setStaticImportOnDemandThreshold(2); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + StringBuilder buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import static java.lang.Math.pow;\n"); + buf.append("import static java.lang.Math.sqrt;\n"); + buf.append("\n"); + buf.append("public class E {\n"); + buf.append("\n"); + buf.append(" public E() {\n"); + buf.append(" double d1 = sqrt(4);\n"); + buf.append(" double d2 = pow(2, 2);\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu = pack1.createCompilationUnit("E.java", buf.toString(), false, null); + buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import static java.lang.Math.*;\n"); + buf.append("\n"); + buf.append("public class E {\n"); + buf.append("\n"); + buf.append(" public E() {\n"); + buf.append(" double d1 = sqrt(4);\n"); + buf.append(" double d2 = pow(2, 2);\n"); + buf.append(" }\n"); + buf.append("}\n"); + Expected e1 = new Expected("Organize imports", buf.toString()); + assertCodeActions(cu, e1); + } finally { + preferenceManager.getPreferences().setStaticImportOnDemandThreshold(staticOnDemandTreshold); + } + } + @Test public void testOrganizeImportsAutomaticallyResolve() throws Exception { 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 d42c4a5af9..41332c1f2a 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 @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -2616,6 +2617,58 @@ public void testStaticImports2() throws Exception { } } + @Test + public void testStarImports() throws Exception { + List favorites = new ArrayList<>(); + favorites.add("java.lang.Math.*"); + Preferences prefs = PreferenceManager.getPrefs(null); + List oldFavorites = Arrays.asList(prefs.getJavaCompletionFavoriteMembers()); + int onDemandThreshold = prefs.getImportOnDemandThreshold(); + int staticOnDemandThreshold = prefs.getStaticImportOnDemandThreshold(); + prefs.setJavaCompletionFavoriteMembers(favorites); + prefs.setImportOnDemandThreshold(2); + prefs.setStaticImportOnDemandThreshold(2); + try { + ICompilationUnit unit = getWorkingCopy("src/test1/B.java", + //@formatter:off + "package test1;\n" + + "import static java.lang.Math.sqrt;\n" + + "import java.util.List;\n" + + "public class B {\n" + + " List list = new ArrayL\n" + + " public static void main(String[] args) {\n" + + " double d1 = sqrt(4);\n" + + " double d2 = abs\n" + + " }\n" + + "}\n"); + //@formatter:on + int[] loc = findCompletionLocation(unit, "new ArrayL"); + CompletionList list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + assertTrue(list.getItems().size() > 0); + CompletionItem item = list.getItems().stream().filter(i -> "ArrayList()".equals(i.getLabel())).collect(Collectors.toList()).get(0); + assertNotNull(item); + List textEdits = item.getAdditionalTextEdits(); + assertEquals(1, textEdits.size()); + TextEdit textEdit = textEdits.get(0); + assertEquals("\n\nimport java.util.*;", textEdit.getNewText()); + loc = findCompletionLocation(unit, "= abs"); + list = server.completion(JsonMessageHelper.getParams(createCompletionRequest(unit, loc[0], loc[1]))).join().getRight(); + assertNotNull(list); + assertTrue(list.getItems().size() > 0); + item = list.getItems().stream().filter(i -> i.getLabel().startsWith("abs(double")).collect(Collectors.toList()).get(0); + assertNotNull(item); + textEdits = item.getAdditionalTextEdits(); + assertEquals(1, textEdits.size()); + textEdit = textEdits.get(0); + assertEquals("import static java.lang.Math.*;\n\n", textEdit.getNewText()); + } finally { + prefs.setJavaCompletionFavoriteMembers(oldFavorites); + prefs.setImportOnDemandThreshold(onDemandThreshold); + prefs.setStaticImportOnDemandThreshold(staticOnDemandThreshold); + } + } + @Test public void testCompletion_linksInMarkdown() throws JavaModelException{ ClientPreferences mockCapabilies = Mockito.mock(ClientPreferences.class);