[Java] IDEA-384756 Do not highlight unresolved static imports as unused if there is method call in class body

GitOrigin-RevId: 7993fc10670ee16dffa38177a1dd99ca42ac5cbb
This commit is contained in:
Georgii Ustinov
2026-01-19 18:18:58 +00:00
committed by intellij-monorepo-bot
parent 633f5708c0
commit ae1cf47d13
6 changed files with 53 additions and 5 deletions
@@ -376,6 +376,11 @@ public final class LocalRefUseInfo {
if (resolveResult.getCurrentFileResolveScope() instanceof PsiImportStatementBase importStatement) {
registerImportStatement(importStatement);
} else if (ref instanceof PsiJavaCodeReferenceElement javaRef &&
isMethodCallResolvedToLocalVariable(refElement, javaRef)) {
for (PsiImportStatementBase potentialImport : IncompleteModelUtil.getPotentialImports(javaRef, false)) {
registerImportStatement(potentialImport);
}
}
else if (refElement == null && ref instanceof PsiJavaReference javaReference) {
JavaResolveResult[] results = javaReference.multiResolve(true);
@@ -464,6 +469,11 @@ public final class LocalRefUseInfo {
registerConstructorCall(enumConstant);
}
private static boolean isMethodCallResolvedToLocalVariable(@Nullable PsiElement refElement, @NotNull PsiJavaCodeReferenceElement javaRef) {
return javaRef.getParent() instanceof PsiMethodCallExpression &&
refElement instanceof PsiLocalVariable;
}
private void registerConstructorCall(@NotNull PsiConstructorCall constructorCall) {
if (constructorCall.resolveMethodGenerics().getElement() instanceof PsiNamedElement namedElement) {
registerLocallyReferenced(namedElement);
@@ -206,7 +206,6 @@ public class UnusedImportsVisitor extends JavaElementVisitor {
if (isRedundantImport(javaFile, importStatement, state.refCountHolder)) {
redundantImports.add(importStatement);
}
else {
int entryIndex = JavaCodeStyleManager.getInstance(javaFile.getProject()).findEntryIndex(importStatement);
if (entryIndex < state.currentEntryIndex && !state.requiresFix) {
@@ -272,7 +271,7 @@ public class UnusedImportsVisitor extends JavaElementVisitor {
myState.builderList.add(builder);
if (!predefinedImport && !myState.requiresFix) {
if (!predefinedImport && !myState.requiresFix/* && importStatement.resolve() != null*/) {
myState.requiresFix = true;
}
}
@@ -213,11 +213,19 @@ public final class IncompleteModelUtil {
PsiTypes.nullType().equals(initializerType) && mayHaveNullTypeDueToPendingReference(initializer);
}
/**
* @see #getPotentialImports(PsiJavaCodeReferenceElement, boolean)
*/
public static @NotNull List<PsiImportStatementBase> getPotentialImports(@NotNull PsiJavaCodeReferenceElement ref) {
return getPotentialImports(ref, true);
}
/**
* @param ref unresolved reference to find potential imports for
* @param ignoreResolvableStaticImports if true, static imports that resolved to a class are filtered out.
* @return list of import statements that potentially import the given unresolved reference
*/
public static List<PsiImportStatementBase> getPotentialImports(@NotNull PsiJavaCodeReferenceElement ref) {
public static @NotNull List<PsiImportStatementBase> getPotentialImports(@NotNull PsiJavaCodeReferenceElement ref, boolean ignoreResolvableStaticImports) {
PsiElement parent = ref.getParent();
if (parent instanceof PsiImportStatementBase || ref.isQualified()) return Collections.emptyList();
boolean maybeClass = canBeClassReference(ref);
@@ -226,7 +234,7 @@ public final class IncompleteModelUtil {
List<PsiImportStatementBase> imports = new ArrayList<>();
if (list != null) {
for (PsiImportStatementBase statement : list.getAllImportStatements()) {
if (statement instanceof PsiImportStaticStatement && ((PsiImportStaticStatement)statement).resolveTargetClass() != null) continue;
if (statement instanceof PsiImportStaticStatement && ((PsiImportStaticStatement)statement).resolveTargetClass() != null && ignoreResolvableStaticImports) continue;
if (!statement.isOnDemand()) {
PsiJavaCodeReferenceElement reference = statement.getImportReference();
if (reference == null) continue;
@@ -0,0 +1,8 @@
import static foo.Util.<error descr="Cannot resolve symbol 'baz'">baz</error>;
class Test {
void test() {
Object <warning descr="Variable 'baz' is never used">baz</warning> = null;
<error descr="Method call expected">baz()</error>;
}
}
@@ -0,0 +1,8 @@
import static <error descr="Cannot resolve symbol 'foo'">foo</error>.bar.baz;
class Test {
void test() {
Object <warning descr="Variable 'baz' is never used">baz</warning> = null;
<error descr="Method call expected">baz()</error>;
}
}
@@ -44,7 +44,6 @@ import com.intellij.util.concurrency.AppExecutorUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
import java.util.concurrent.ExecutionException;
public class OptimizeImportsTest extends OptimizeImportsTestCase {
static final String BASE_PATH = PathManagerEx.getTestDataPath() + "/psi/optimizeImports";
@@ -493,6 +492,22 @@ public class OptimizeImportsTest extends OptimizeImportsTestCase {
checkOptimizeImportNoIntention();
}
public void testOptimizeImportNotOnTheFlyInvalidStaticImportPackageNoIntention() {
checkOptimizeImportNoIntention();
}
public void testOptimizeImportNotOnTheFlyInvalidStaticImportClassNoIntention() {
myFixture.addFileToProject(
"foo/Util.java",
"""
package foo;
public class Util {}
"""
);
checkOptimizeImportNoIntention();
}
public void testOptimizeImportNotOnTheFlyInvalidImportOnDemand() {
checkOptimizeImport();
}