[java-inspections] IDEA-371026 Exclusions from static imports

GitOrigin-RevId: a7972852a7bad35c7e1355cdc8177e84aac4a4e8
This commit is contained in:
Mikhail Pyltsin
2025-11-06 10:54:59 +01:00
committed by intellij-monorepo-bot
parent 4cb9f02526
commit 254e3e83ac
15 changed files with 635 additions and 249 deletions

View File

@@ -124,10 +124,10 @@ abstract class ImportTable extends ListTableWithButtons<ImportTable.Item> implem
new ComponentValidator(validatorsDisposable).withValidator(() -> {
String text = cellEditor.getText();
boolean hasError = !StringUtil.isEmpty(text) && !ourPackagePattern.matcher(text).matches();
ValidationInfo info = validate(text, cellEditor);
boolean hasError = info != null;
ValidationUtils.setExtension(cellEditor, ValidationUtils.ERROR_EXTENSION, hasError);
return validationInfoProducer.apply(text, cellEditor);
return info;
}).andRegisterOnDocumentListener(cellEditor).installOn(cellEditor);
return new DefaultCellEditor(cellEditor);
@@ -139,7 +139,7 @@ abstract class ImportTable extends ListTableWithButtons<ImportTable.Item> implem
cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE);
return new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()).
withCellValidator((value, row, column) -> validationInfoProducer.apply(value, null)).
withCellValidator((value, row, column) -> validate(value, null)).
bindToEditorSize(cellEditor::getPreferredSize);
}
@@ -155,6 +155,10 @@ abstract class ImportTable extends ListTableWithButtons<ImportTable.Item> implem
};
}
protected @Nullable ValidationInfo validate(@Nullable Object value, @Nullable JComponent component) {
return validationInfoProducer.apply(value, component);
}
@Override
protected Item createElement() {
return new Item("", Scope.IDE);

View File

@@ -17,6 +17,7 @@ import com.intellij.openapi.options.UiDslUnnamedConfigurable
import com.intellij.openapi.options.ex.Settings
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.ui.ValidationInfo
import com.intellij.openapi.util.Disposer
import com.intellij.ui.ContextHelpLabel
import com.intellij.ui.IdeUICustomization
@@ -51,6 +52,15 @@ public class JavaAutoImportOptions(public val project: Project) : UiDslUnnamedCo
JavaBundle.message("auto.static.import.class"),
JavaBundle.message("auto.static.import.scope")) {
override fun validate(value: Any?, component: JComponent?): ValidationInfo? {
val info = super.validate(value, component)
if (info != null && value is String && value.startsWith("-")) {
val cutInfo = super.validate(value.substring(1), component)
if (cutInfo == null) return null
}
return info
}
override fun getIdeRows(): Array<out String> {
return JavaIdeCodeInsightSettings.getInstance().includedAutoStaticNames.toTypedArray()
}

View File

@@ -25,6 +25,7 @@ import org.jetbrains.annotations.TestOnly;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
@@ -43,10 +44,34 @@ public class JavaProjectCodeInsightSettings implements PersistentStateComponent<
return project.getService(JavaProjectCodeInsightSettings.class);
}
public List<String> getAllIncludedAutoStaticNames() {
public AutoStaticNameContainer getAllIncludedAutoStaticNames() {
List<String> names = new ArrayList<>(includedAutoStaticNames);
names.addAll(JavaIdeCodeInsightSettings.getInstance().includedAutoStaticNames);
return names;
return AutoStaticNameContainer.create(names);
}
public record AutoStaticNameContainer(LinkedHashSet<String> includedNames, LinkedHashSet<String> excludedNames) {
public boolean containsName(@NotNull String name) {
return (includedNames.contains(name) || includedNames.contains(StringUtil.getPackageName(name))) &&
!(excludedNames.contains(name) || excludedNames.contains(StringUtil.getPackageName(name)));
}
public static AutoStaticNameContainer create(List<String> allNames) {
LinkedHashSet<String> includedNames = new LinkedHashSet<>();
LinkedHashSet<String> excludedNames = new LinkedHashSet<>();
for (String name : allNames) {
if (name == null) continue;
if (StringUtil.isEmptyOrSpaces(name)) continue;
if (name.startsWith("-")) {
excludedNames.add(name.substring(1));
}
else {
includedNames.add(name);
}
}
return new AutoStaticNameContainer(includedNames, excludedNames);
}
}
/**
@@ -58,8 +83,8 @@ public class JavaProjectCodeInsightSettings implements PersistentStateComponent<
*/
public boolean isStaticAutoImportName(@Nullable String name) {
if (name == null) return false;
List<String> names = getAllIncludedAutoStaticNames();
return names.contains(name) || names.contains(StringUtil.getPackageName(name));
AutoStaticNameContainer names = getAllIncludedAutoStaticNames();
return names.containsName(name);
}
public boolean isExcluded(@NotNull String name) {

View File

@@ -42,24 +42,42 @@ public class JavaStaticMemberProcessor extends StaticMemberProcessor {
JavaProjectCodeInsightSettings codeInsightSettings = JavaProjectCodeInsightSettings.getSettings(project);
JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
GlobalSearchScope resolveScope = parameters.getOriginalFile().getResolveScope();
for (String name : codeInsightSettings.getAllIncludedAutoStaticNames()) {
JavaProjectCodeInsightSettings.AutoStaticNameContainer autoContainer = codeInsightSettings.getAllIncludedAutoStaticNames();
for (String name : autoContainer.includedNames()) {
PsiClass aClass = javaPsiFacade.findClass(name, resolveScope);
if (aClass != null && isAccessibleClass(aClass)) {
importMembersOf(aClass);
if (aClass != null &&
aClass.getQualifiedName() != null &&
isAccessibleClass(aClass)) {
for (PsiMethod method : aClass.getAllMethods()) {
if (method.hasModifierProperty(PsiModifier.STATIC) &&
autoContainer.containsName(aClass.getQualifiedName() + "." + method.getName())) {
importMember(method);
}
}
for (PsiField psiField : aClass.getAllFields()) {
if (psiField.hasModifierProperty(PsiModifier.STATIC) &&
autoContainer.containsName(aClass.getQualifiedName() + "." + psiField.getName())) {
importMember(psiField);
}
}
}
else {
String shortMemberName = StringUtil.getShortName(name);
String containingMemberName = StringUtil.getPackageName(name);
if (containingMemberName.isEmpty() || shortMemberName.isEmpty()) continue;
PsiClass containingClass = javaPsiFacade.findClass(containingMemberName, resolveScope);
if (containingClass != null && isAccessibleClass(containingClass)) {
if (containingClass == null || containingClass.getQualifiedName() == null) continue;
if (isAccessibleClass(containingClass)) {
for (PsiMethod method : containingClass.findMethodsByName(shortMemberName, true)) {
if (method.hasModifierProperty(PsiModifier.STATIC)) {
if (method.hasModifierProperty(PsiModifier.STATIC) &&
autoContainer.containsName(containingClass.getQualifiedName() + "." + method.getName())) {
importMember(method);
}
}
PsiField psiField = containingClass.findFieldByName(shortMemberName, true);
if (psiField != null && psiField.hasModifierProperty(PsiModifier.STATIC)) {
if (psiField != null &&
psiField.hasModifierProperty(PsiModifier.STATIC) &&
autoContainer.containsName(containingClass.getQualifiedName() + "." + psiField.getName())) {
importMember(psiField);
}
}

View File

@@ -139,7 +139,7 @@ public abstract class StaticMemberProcessor {
}
}
private boolean isStaticallyImportable(@NotNull PsiMember member) {
protected boolean isStaticallyImportable(@NotNull PsiMember member) {
return member.hasModifierProperty(PsiModifier.STATIC) && isAccessible(member) && !isExcluded(member);
}

View File

@@ -18,7 +18,6 @@ import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -28,15 +27,15 @@ public final class StaticImportCanBeUsedInspection extends AbstractBaseJavaLocal
boolean isOnTheFly,
@NotNull LocalInspectionToolSession session) {
JavaProjectCodeInsightSettings settings = JavaProjectCodeInsightSettings.getSettings(holder.getProject());
List<String> names = settings.getAllIncludedAutoStaticNames();
if (names.isEmpty()) {
JavaProjectCodeInsightSettings.AutoStaticNameContainer autoStaticNames = settings.getAllIncludedAutoStaticNames();
if (autoStaticNames.includedNames().isEmpty()) {
return PsiElementVisitor.EMPTY_VISITOR;
}
Set<String> shortNames = names.stream()
Set<String> shortNames = autoStaticNames.includedNames().stream()
.map(name -> StringUtil.getShortName(name))
.collect(Collectors.toSet());
Set<String> classShortNames = names.stream()
Set<String> classShortNames = autoStaticNames.includedNames().stream()
.map(name -> StringUtil.getShortName(StringUtil.getPackageName(name)))
.filter(name -> !name.isBlank())
.collect(Collectors.toSet());
@@ -57,11 +56,47 @@ public final class StaticImportCanBeUsedInspection extends AbstractBaseJavaLocal
holder.registerProblem(qualifierReference,
JavaBundle.message("inspection.static.import.can.be.used.display.name"),
new StaticImportFix(),
new DeleteSettingsFromAutoImportTable(context.fqn));
new DeleteSettingsFromAutoImportTable(context.fqn),
new AddExclusionFromAutoImportTable(context.fqn));
}
};
}
private static class AddExclusionFromAutoImportTable extends ModCommandQuickFix {
private final String myFqn;
private AddExclusionFromAutoImportTable(String fqn) { myFqn = fqn; }
@Override
public @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (element == null) return ModCommand.nop();
JavaIdeCodeInsightSettings settings = JavaIdeCodeInsightSettings.getInstance();
if (settings.includedAutoStaticNames.contains(myFqn) || settings.includedAutoStaticNames.contains(StringUtil.getPackageName(myFqn))) {
return ModCommand.updateOptionList(element,
"JavaIdeCodeInsightSettings.includedAutoStaticNames",
strings -> {
strings.add("-" + myFqn);
});
}
return ModCommand.updateOptionList(element,
"JavaProjectCodeInsightSettings.includedAutoStaticNames",
strings -> {
strings.add("-" + myFqn);
});
}
@Override
public @NotNull String getName() {
return JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", myFqn);
}
@Override
public @NotNull String getFamilyName() {
return JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.family.name");
}
}
private static class DeleteSettingsFromAutoImportTable extends ModCommandQuickFix {
private final String myFqn;
@@ -76,15 +111,19 @@ public final class StaticImportCanBeUsedInspection extends AbstractBaseJavaLocal
return ModCommand.updateOptionList(element,
"JavaIdeCodeInsightSettings.includedAutoStaticNames",
strings -> {
strings.remove(myFqn);
strings.remove(StringUtil.getPackageName(myFqn));
strings.removeIf(t ->
t.startsWith(StringUtil.getPackageName(myFqn)) ||
t.startsWith("-" + StringUtil.getPackageName(myFqn))
);
});
}
return ModCommand.updateOptionList(element,
"JavaProjectCodeInsightSettings.includedAutoStaticNames",
strings -> {
strings.remove(myFqn);
strings.remove(StringUtil.getPackageName(myFqn));
strings.removeIf(t->
t.startsWith(StringUtil.getPackageName(myFqn)) ||
t.startsWith("-" + StringUtil.getPackageName(myFqn))
);
});
}

View File

@@ -0,0 +1,8 @@
import java.util.List;
class Foo {
void test(List<String> baz) {
<caret>
}
}

View File

@@ -0,0 +1,10 @@
import java.util.List;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
class Foo {
void test(List<String> baz) {
NANO_OF_SECOND<caret>
}
}

View File

@@ -0,0 +1,8 @@
import java.util.List;
class Foo {
void test(List<String> baz) {
<caret>
}
}

View File

@@ -0,0 +1,8 @@
import java.util.List;
class Foo {
void test(List<String> baz) {
<caret>
}
}

View File

@@ -0,0 +1,10 @@
import java.util.List;
import static java.time.temporal.ChronoField.values;
class Foo {
void test(List<String> baz) {
values()<caret>
}
}

View File

@@ -0,0 +1,10 @@
package staticImportCanBeUsed;
import java.util.Arrays;
class Foo {
void test(String[] baz) {
Arrays<caret>.sort(baz);
Arrays.sort(baz);
}
}

View File

@@ -23,7 +23,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest
@Override
public void tearDown() throws Exception {
try {
JavaProjectCodeInsightSettings.getSettings(getProject()).includedAutoStaticNames.clear();
cleanTable();
}
catch (Throwable e) {
addSuppressedException(e);
@@ -33,6 +33,11 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest
}
}
private void cleanTable() {
JavaProjectCodeInsightSettings.getSettings(getProject()).includedAutoStaticNames.clear();
JavaIdeCodeInsightSettings.getInstance().includedAutoStaticNames.clear();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
@@ -40,33 +45,99 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest
}
public void testSimple() {
addStaticAutoImport("java.util.Arrays");
doTest();
cleanupTest();
try {
addStaticAutoImport("java.util.Arrays");
doTest();
cleanupTest();
}
finally {
cleanTable();
}
}
public void testSimpleWithExclusion() {
try {
addStaticAutoImport("java.util.Arrays");
addStaticAutoImport("-java.util.Arrays.sort");
doTest();
}
finally {
cleanTable();
}
}
public void testRemoveAutoImportProject() {
addStaticAutoImport("java.util.Arrays");
doTest();
IntentionAction intention = myFixture.getAvailableIntention(
JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort"));
myFixture.launchAction(intention);
checkAutoImportDoesntContain("java.util.Arrays");
try {
addStaticAutoImport("java.util.Arrays");
addStaticAutoImport("-java.util.Arrays.binarySearch");
doTest();
IntentionAction intention = myFixture.getAvailableIntention(
JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort"));
myFixture.launchAction(intention);
checkAutoImportDoesntContain("java.util.Arrays");
}
finally {
cleanTable();
}
}
public void testExcludeAutoImportProject() {
try {
addStaticAutoImport("java.util.Arrays");
addStaticAutoImport("-java.util.Arrays.binarySearch");
doNamedTest("RemoveAutoImportProject");
IntentionAction intention = myFixture.getAvailableIntention(
JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", "java.util.Arrays.sort"));
myFixture.launchAction(intention);
checkAutoImportContains("java.util.Arrays");
checkAutoImportDoesntContain("java.util.Arrays.sort");
checkAutoImportDoesntContain("java.util.Arrays.binarySearch");
}
finally {
cleanTable();
}
}
public void testRemoveAutoImportIde() {
addStaticAutoImportToIde("java.util.Arrays");
doTest();
IntentionAction intention = myFixture.getAvailableIntention(
JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort"));
myFixture.launchAction(intention);
checkAutoImportDoesntContain("java.util.Arrays");
try {
addStaticAutoImportToIde("java.util.Arrays");
addStaticAutoImportToIde("-java.util.Arrays.binarySearch");
doTest();
IntentionAction intention = myFixture.getAvailableIntention(
JavaBundle.message("inspection.static.import.can.be.used.remove.from.auto.import.name", "java.util.Arrays.sort"));
myFixture.launchAction(intention);
checkAutoImportDoesntContain("java.util.Arrays");
}
finally {
cleanTable();
}
}
public void testExcludeAutoImportIde() {
try {
addStaticAutoImportToIde("java.util.Arrays");
addStaticAutoImportToIde("-java.util.Arrays.binarySearch");
doNamedTest("RemoveAutoImportIde");
IntentionAction intention = myFixture.getAvailableIntention(
JavaBundle.message("inspection.static.import.can.be.used.exclude.from.auto.import.name", "java.util.Arrays.sort"));
myFixture.launchAction(intention);
checkAutoImportContains("java.util.Arrays");
checkAutoImportDoesntContain("java.util.Arrays.sort");
checkAutoImportDoesntContain("java.util.Arrays.binarySearch");
}
finally {
cleanTable();
}
}
private void checkAutoImportDoesntContain(@NotNull String fqn) {
assertFalse(JavaCodeStyleManager.getInstance(getProject()).isStaticAutoImportName(fqn));
}
private void checkAutoImportContains(@NotNull String fqn) {
assertTrue(JavaCodeStyleManager.getInstance(getProject()).isStaticAutoImportName(fqn));
}
public void testSimpleWithOnDemand() {
addStaticAutoImport("java.util.Arrays");
JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());
@@ -80,13 +151,19 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest
}
finally {
onDemand.removeEntryAt(onDemandLength);
cleanTable();
}
}
public void testSimpleMethod() {
addStaticAutoImport("java.util.Arrays.sort");
doTest();
cleanupTest();
try {
addStaticAutoImport("java.util.Arrays.sort");
doTest();
cleanupTest();
}
finally {
cleanTable();
}
}
public void testSimpleMethodOnDemand() {
@@ -101,71 +178,97 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest
cleanupTest();
}
finally {
cleanTable();
onDemand.removeEntryAt(onDemandLength);
}
}
public void testWithConflicts() {
addStaticAutoImport("java.util.Arrays");
doTest();
try {
addStaticAutoImport("java.util.Arrays");
doTest();
}
finally {
cleanTable();
}
}
public void testWithConflicts2() {
addStaticAutoImport("java.util.Arrays");
myFixture.addClass("""
package org;
public final class Foo2 {
public static void binarySearch(Object[] args, Object key) {}
}
""");
doTest();
try {
addStaticAutoImport("java.util.Arrays");
myFixture.addClass("""
package org;
public final class Foo2 {
public static void binarySearch(Object[] args, Object key) {}
}
""");
doTest();
}
finally {
cleanTable();
}
}
public void testWithConflictsWithField() {
addStaticAutoImport("org.Foo2");
myFixture.addClass("""
package org;
public final class Foo2 {
public static final String PI = "3.14"
public static void sort(String[] args) {}
}
""");
myFixture.addClass("""
package org;
public final class Foo3 {
public static final String PI = "3.14"
}
""");
doTest();
try {
addStaticAutoImport("org.Foo2");
myFixture.addClass("""
package org;
public final class Foo2 {
public static final String PI = "3.14"
public static void sort(String[] args) {}
}
""");
myFixture.addClass("""
package org;
public final class Foo3 {
public static final String PI = "3.14"
}
""");
doTest();
}
finally {
cleanTable();
}
}
public void testWithConflictsWithClass() {
addStaticAutoImport("org.Foo2");
myFixture.addClass("""
package org;
public final class Foo2 {
public static class Calculus{}
public static void sort(String[] args) {}
}
""");
myFixture.addClass("""
package org;
public final class Foo3 {
public static class Calculus{}
}
""");
doTest();
try {
addStaticAutoImport("org.Foo2");
myFixture.addClass("""
package org;
public final class Foo2 {
public static class Calculus{}
public static void sort(String[] args) {}
}
""");
myFixture.addClass("""
package org;
public final class Foo3 {
public static class Calculus{}
}
""");
doTest();
}
finally {
cleanTable();
}
}
public void testAlreadyImported() {
addStaticAutoImport("java.util.Arrays");
doTest();
cleanupTest();
try {
addStaticAutoImport("java.util.Arrays");
doTest();
cleanupTest();
}
finally {
cleanTable();
}
}
private void cleanupTest() {
@@ -183,6 +286,7 @@ public class StaticImportCanBeUsedInspectionTest extends LightJavaInspectionTest
private void addStaticAutoImport(@NotNull String name) {
JavaProjectCodeInsightSettings.getSettings(getProject()).includedAutoStaticNames.add(name);
}
private static void addStaticAutoImportToIde(@NotNull String name) {
JavaIdeCodeInsightSettings.getInstance().includedAutoStaticNames.add(name);
}

View File

@@ -6,6 +6,7 @@ import com.intellij.codeInsight.JavaProjectCodeInsightSettings;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.codeStyle.PackageEntry;
@@ -22,7 +23,7 @@ public class AutoStaticImportCompletionTest extends NormalCompletionTestCase {
@Override
public void tearDown() throws Exception {
try {
JavaProjectCodeInsightSettings.getSettings(getProject()).includedAutoStaticNames.clear();
clear();
}
catch (Throwable e) {
addSuppressedException(e);
@@ -32,6 +33,10 @@ public class AutoStaticImportCompletionTest extends NormalCompletionTestCase {
}
}
private void clear() {
JavaProjectCodeInsightSettings.getSettings(getProject()).includedAutoStaticNames.clear();
}
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
@@ -44,33 +49,104 @@ public class AutoStaticImportCompletionTest extends NormalCompletionTestCase {
}
public void testSimpleStaticAutoImport() {
addStaticAutoImport("java.util.Arrays");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
try {
addStaticAutoImport("java.util.Arrays");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNotNull(element);
selectItem(element);
}
checkResult();
}
finally {
clear();
}
}
public void testExcludeAutoImport() {
try {
addStaticAutoImport("java.util.Arrays");
addStaticAutoImport("-java.util.Arrays.sort");
configure();
LookupElement[] elements = myFixture.getLookupElements();
assertNotNull(elements);
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNull(element);
}
finally {
clear();
}
}
public void testFullAutoImportEnum() {
try {
addStaticAutoImport("java.time.temporal.ChronoField");
configure();
LookupElement[] elements = myFixture.getLookupElements();
assertNotNull(elements);
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("values") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.time.temporal.ChronoField"));
assertNotNull(element);
selectItem(element);
checkResult();
}
finally {
clear();
}
}
public void testAutoImportEnumWithExclusion() {
try {
addStaticAutoImport("java.time.temporal.ChronoField");
addStaticAutoImport("-java.time.temporal.ChronoField.values");
configure();
LookupElement[] elements = myFixture.getLookupElements();
assertNotNull(elements);
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("values") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.time.temporal.ChronoField"));
assertNull(element);
element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("NANO_OF_SECOND") &&
e.getPsiElement() instanceof PsiField psiField &&
psiField.getContainingClass().getQualifiedName().equals("java.time.temporal.ChronoField"));
selectItem(element);
checkResult();
}
finally {
clear();
}
checkResult();
}
public void testSimpleMethodStaticAutoImport() {
addStaticAutoImport("java.util.Arrays.sort");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNotNull(element);
selectItem(element);
try {
addStaticAutoImport("java.util.Arrays.sort");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNotNull(element);
selectItem(element);
}
checkResult();
}
finally {
clear();
}
checkResult();
}
public void testSimpleMethodStaticAutoImportOnDemand() {
@@ -94,20 +170,26 @@ public class AutoStaticImportCompletionTest extends NormalCompletionTestCase {
checkResult();
}
finally {
clear();
onDemand.removeEntryAt(onDemandLength);
}
}
public void testSimpleMethodStaticAutoImportNotFound() {
addStaticAutoImport("java.util.Arrays.binarySearch");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNull(element);
try {
addStaticAutoImport("java.util.Arrays.binarySearch");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNull(element);
}
}
finally {
clear();
}
}
@@ -132,47 +214,58 @@ public class AutoStaticImportCompletionTest extends NormalCompletionTestCase {
checkResult();
}
finally {
clear();
onDemand.removeEntryAt(onDemandLength);
}
}
@NeedsIndex.Full
public void testSimpleStaticAutoImportWithConflict() {
addStaticAutoImport("java.util.Arrays");
myFixture.addClass("""
package org.example;
public final class AAA {
public static <T> List<T> sort(T[] args){
return null;
try {
addStaticAutoImport("java.util.Arrays");
myFixture.addClass("""
package org.example;
public final class AAA {
public static <T> List<T> sort(T[] args){
return null;
}
}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNotNull(element);
selectItem(element);
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNotNull(element);
selectItem(element);
}
checkResult();
}
finally {
clear();
}
checkResult();
}
public void testSimpleStaticAutoImportWithAlreadyImported() {
addStaticAutoImport("java.util.Arrays");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNotNull(element);
selectItem(element);
try {
addStaticAutoImport("java.util.Arrays");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("sort") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Arrays"));
assertNotNull(element);
selectItem(element);
}
checkResult();
}
finally {
clear();
}
checkResult();
}
public void testNoAutoImport() {
@@ -189,30 +282,40 @@ public class AutoStaticImportCompletionTest extends NormalCompletionTestCase {
@NeedsIndex.Full
public void testChainedAutoStaticImport() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_1_8, () -> {
addStaticAutoImport("java.util.stream.Collectors");
configureByTestName();
selectItem(ContainerUtil.find(myItems, it -> it.getLookupString().contains("toList")));
checkResult();
});
try {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_1_8, () -> {
addStaticAutoImport("java.util.stream.Collectors");
configureByTestName();
selectItem(ContainerUtil.find(myItems, it -> it.getLookupString().contains("toList")));
checkResult();
});
}
finally {
clear();
}
}
@NeedsIndex.Full
public void testChainedAutoStaticImportWithConflict() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_1_8, () -> {
addStaticAutoImport("java.util.stream.Collectors");
myFixture.addClass("""
package org.example;
public final class AAA {
public static <T> List<T> toList(){
return null;
try {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_1_8, () -> {
addStaticAutoImport("java.util.stream.Collectors");
myFixture.addClass("""
package org.example;
public final class AAA {
public static <T> List<T> toList(){
return null;
}
}
}
""");
configureByTestName();
selectItem(ContainerUtil.find(myItems, it -> it.getLookupString().contains("toList")));
checkResult();
});
""");
configureByTestName();
selectItem(ContainerUtil.find(myItems, it -> it.getLookupString().contains("toList")));
checkResult();
});
}
finally {
clear();
}
}
public void testNoSimpleStaticAutoImport() {
@@ -229,22 +332,27 @@ public class AutoStaticImportCompletionTest extends NormalCompletionTestCase {
@NeedsIndex.Full
public void testWithPackageConflicts() {
addStaticAutoImport("java.util.Objects");
myFixture.addClass("""
package requireNonNull;
public final class Dummy {}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("requireNonNull") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Objects"));
assertNotNull(element);
selectItem(element);
try {
addStaticAutoImport("java.util.Objects");
myFixture.addClass("""
package requireNonNull;
public final class Dummy {}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("requireNonNull") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("java.util.Objects"));
assertNotNull(element);
selectItem(element);
}
checkResult();
}
finally {
clear();
}
checkResult();
}
@NeedsIndex.Full
@@ -273,95 +381,116 @@ public class AutoStaticImportCompletionTest extends NormalCompletionTestCase {
checkResult();
}
finally {
clear();
onDemand.removeEntryAt(onDemandLength);
}
}
@NeedsIndex.Full
public void testWithMemberConflicts() {
addStaticAutoImport("a.Objects");
myFixture.addClass("""
package a;
public final class Objects {
public static <T> T requireNonNull(T obj) {}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("requireNonNull") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("a.Objects"));
assertNotNull(element);
selectItem(element);
try {
addStaticAutoImport("a.Objects");
myFixture.addClass("""
package a;
public final class Objects {
public static <T> T requireNonNull(T obj) {}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("requireNonNull") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("a.Objects"));
assertNotNull(element);
selectItem(element);
}
checkResult();
}
finally {
clear();
}
checkResult();
}
@NeedsIndex.Full
public void testDefaultPackage() {
addStaticAutoImport("Foo.bar");
myFixture.addClass("""
public final class Foo {
public static void bar() {}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("bar") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("Foo"));
assertNotNull(element);
selectItem(element);
try {
addStaticAutoImport("Foo.bar");
myFixture.addClass("""
public final class Foo {
public static void bar() {}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("bar") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("Foo"));
assertNotNull(element);
selectItem(element);
}
checkResult();
}
finally {
clear();
}
checkResult();
}
@NeedsIndex.Full
public void testDefaultPackageFromNonDefaultPackage() {
addStaticAutoImport("Foo.bar");
myFixture.addClass("""
public final class Foo {
public static void bar() {}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("bar") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("Foo"));
assertNull(element);
try {
addStaticAutoImport("Foo.bar");
myFixture.addClass("""
public final class Foo {
public static void bar() {}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("bar") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("Foo"));
assertNull(element);
}
}
finally {
clear();
}
}
@NeedsIndex.Full
public void testShowPackage() {
addStaticAutoImport("org.example.Foo.bar");
myFixture.addClass("""
package org.example;
public final class Foo {
public static void bar() {}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("bar") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("org.example.Foo"));
assertNotNull(element);
LookupElementPresentation presentation = new LookupElementPresentation();
element.renderElement(presentation);
assertTrue(presentation.getTailText().contains("org.example"));
selectItem(element);
try {
addStaticAutoImport("org.example.Foo.bar");
myFixture.addClass("""
package org.example;
public final class Foo {
public static void bar() {}
}
""");
configure();
LookupElement[] elements = myFixture.getLookupElements();
if (elements != null) {
LookupElement element = ContainerUtil.find(elements, e ->
e.getLookupString().equals("bar") &&
e.getPsiElement() instanceof PsiMethod method &&
method.getContainingClass().getQualifiedName().equals("org.example.Foo"));
assertNotNull(element);
LookupElementPresentation presentation = new LookupElementPresentation();
element.renderElement(presentation);
assertTrue(presentation.getTailText().contains("org.example"));
selectItem(element);
}
checkResult();
}
finally {
clear();
}
checkResult();
}
private void addStaticAutoImport(@NotNull String name) {

View File

@@ -199,7 +199,8 @@ auto.static.import.comment.project=Include auto-import of static members in comp
auto.static.import.comment.ide=Include auto-import of static members in completion IDE settings:
auto.static.import.class=Class or static members
auto.static.import.scope=Scope
auto.static.import.example=Examples: 'java.util.Objects' or 'java.util.Objects.requireNonNull'
auto.static.import.example=Examples: 'java.util.Objects' or 'java.util.Objects.requireNonNull'. \
Use '-' to exclude, for example: '-java.util.Objects.requireNonNull'
exclude.from.imports.no.exclusions=Add a class, package, or member to exclude from auto-import and completion
exclude.table.mask=Class, Package, or Member
exclude.table.scope.column=Scope
@@ -1444,6 +1445,8 @@ inspection.static.import.can.be.used.display.name=Static import can be used base
inspection.static.import.can.be.used.fix.name=Add static import
inspection.static.import.can.be.used.remove.from.auto.import.family.name=Remove on-demand static import from the auto-import table
inspection.static.import.can.be.used.remove.from.auto.import.name=Remove ''{0}'' and its parent from the auto-import table
inspection.static.import.can.be.used.exclude.from.auto.import.family.name=Add exclusion for on-demand static import to the auto-import table
inspection.static.import.can.be.used.exclude.from.auto.import.name=Add exclusion for ''{0}'' to the auto-import table
slice.filter.parse.error.null.filter.not.applicable.for.primitive.type=''null'' filter is not applicable to primitive type {0}
slice.filter.parse.error.not.null.filter.not.applicable.for.primitive.type=''!null'' filter is not applicable to primitive type {0}