[java-highlighting] Do not mark potential imports for unresolved references as unused

Improves IDEA-353117 Error highlighting in incomplete project model

GitOrigin-RevId: d6419b900fc817c28b7d1b942b28857a14b44141
This commit is contained in:
Tagir Valeev
2024-05-21 12:17:41 +02:00
committed by intellij-monorepo-bot
parent 4ebe1c86dd
commit c26fabffef
5 changed files with 50 additions and 22 deletions

View File

@@ -187,6 +187,35 @@ final class IncompleteModelUtil {
return false;
}
/**
* @param ref unresolved reference to find potential imports for
* @return list of import statements that potentially import the given unresolved reference
*/
static List<PsiImportStatementBase> getPotentialImports(@NotNull PsiJavaCodeReferenceElement ref) {
if (ref.getParent() instanceof PsiImportStatementBase) return List.of();
boolean call = ref.getParent() instanceof PsiMethodCallExpression;
if (!(ref.getContainingFile() instanceof PsiJavaFile file)) return List.of();
PsiImportList list = file.getImportList();
List<PsiImportStatementBase> imports = new ArrayList<>();
if (list != null) {
for (PsiImportStatementBase statement : list.getAllImportStatements()) {
if (statement instanceof PsiImportStaticStatement staticImport && staticImport.resolveTargetClass() != null) continue;
if (!statement.isOnDemand()) {
PsiJavaCodeReferenceElement reference = statement.getImportReference();
if (reference == null) continue;
String name = reference.getReferenceName();
if (name == null || !name.equals(ref.getReferenceName())) continue;
if (reference.resolve() != null) continue;
}
// Unqualified method call cannot be imported using non-static import
if (statement instanceof PsiImportStaticStatement || !call) {
imports.add(statement);
}
}
}
return imports;
}
/**
* @param ref reference to check
* @return true if the reference can be pending. A pending reference is an unresolved reference that can be potentially resolved
@@ -202,24 +231,7 @@ final class IncompleteModelUtil {
if (!isHierarchyResolved(psiClass)) return true;
psiClass = ClassUtils.getContainingClass(psiClass);
}
boolean call = ref.getParent() instanceof PsiMethodCallExpression;
PsiImportList list = ((PsiJavaFile)ref.getContainingFile()).getImportList();
if (list != null) {
for (PsiImportStatementBase statement : list.getAllImportStatements()) {
if (statement instanceof PsiImportStaticStatement staticImport && staticImport.resolveTargetClass() != null) continue;
if (!statement.isOnDemand()) {
PsiJavaCodeReferenceElement reference = statement.getImportReference();
if (reference == null) continue;
String name = reference.getReferenceName();
if (name == null || !name.equals(ref.getReferenceName())) continue;
}
// Unqualified method call cannot be imported using non-static import
if (statement instanceof PsiImportStaticStatement || !call) {
return true;
}
}
}
return false;
return !getPotentialImports(ref).isEmpty();
}
if (qualifier instanceof PsiReferenceExpression qualifierRef) {
PsiElement qualifierTarget = qualifierRef.resolve();

View File

@@ -360,10 +360,17 @@ public final class LocalRefUseInfo {
registerImportStatement(ref, importStatement);
}
else if (refElement == null && ref instanceof PsiJavaReference javaReference) {
for (JavaResolveResult result : javaReference.multiResolve(true)) {
if (result.getCurrentFileResolveScope() instanceof PsiImportStatementBase importStatement) {
registerImportStatement(ref, importStatement);
break;
JavaResolveResult[] results = javaReference.multiResolve(true);
if (results.length > 0) {
for (JavaResolveResult result : results) {
if (result.getCurrentFileResolveScope() instanceof PsiImportStatementBase importStatement) {
registerImportStatement(ref, importStatement);
break;
}
}
} else if (ref instanceof PsiJavaCodeReferenceElement javaRef) {
for (PsiImportStatementBase potentialImport : IncompleteModelUtil.getPotentialImports(javaRef)) {
registerImportStatement(ref, potentialImport);
}
}
}

View File

@@ -5,6 +5,7 @@ import <info descr="Not resolved until the project is fully loaded">com</info>.<
import java.util.HashMap;
import java.util.Map;
<warning descr="Unused import statement">import java.util.TreeMap;</warning>
public class DefaultLoaderFactory implements <info descr="Not resolved until the project is fully loaded">ReportLoaderFactory</info> {
public static final String GROOVY_DATA_LOADER = "groovy";

View File

@@ -1,4 +1,5 @@
import java.util.Map;
import java.io.IOException;
import <info descr="Not resolved until the project is fully loaded">my</info>.<info descr="Not resolved until the project is fully loaded">unknown</info>.<info descr="Not resolved until the project is fully loaded">pkg</info>.<info descr="Not resolved until the project is fully loaded">Anno</info>;
import <info descr="Not resolved until the project is fully loaded">my</info>.<info descr="Not resolved until the project is fully loaded">unknown</info>.<info descr="Not resolved until the project is fully loaded">pkg</info>.<info descr="Not resolved until the project is fully loaded">MyInterface</info>;
import <info descr="Not resolved until the project is fully loaded">my</info>.<info descr="Not resolved until the project is fully loaded">unknown</info>.<info descr="Not resolved until the project is fully loaded">pkg</info>.<info descr="Not resolved until the project is fully loaded">Cls</info>;
@@ -37,6 +38,10 @@ public class Simple {
void method(String s, Object obj) {}
private void methodThrows() throws <warning descr="Exception 'java.io.IOException' is never thrown in the method">IOException</warning> {
System.out.println();
}
void methodCall(<info descr="Not resolved until the project is fully loaded">Unknown</info> u) {
method("Hello", u);
method(<error descr="'method(java.lang.String, java.lang.Object)' in 'Simple' cannot be applied to '(Unknown, java.lang.String)'">u</error>, "Hello");

View File

@@ -2,6 +2,8 @@
package com.intellij.java.codeInsight.daemon.incomplete;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.codeInspection.unneededThrows.RedundantThrowsDeclarationLocalInspection;
import com.intellij.codeInspection.unusedImport.UnusedImportInspection;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.IncompleteDependenciesService;
@@ -15,6 +17,7 @@ public final class IncompleteModelHighlightingTest extends LightDaemonAnalyzerTe
}
private void doTest(String fileName) {
enableInspectionTools(new UnusedImportInspection(), new RedundantThrowsDeclarationLocalInspection());
IncompleteDependenciesService service = getProject().getService(IncompleteDependenciesService.class);
try (var ignored = asAutoCloseable(WriteAction.compute(() -> service.enterIncompleteState()))) {
doTest(BASE_PATH + "/" + fileName, true, true);