[java-highlighting] Incomplete model (IDEA-353117) improvements

Annotations; casts; modules; fix accidental negation

GitOrigin-RevId: 5fee6394cd39b066c1c05b1af93f4fdc9d554b82
This commit is contained in:
Tagir Valeev
2024-05-08 19:27:19 +00:00
committed by intellij-monorepo-bot
parent 77754dbd76
commit 0e644d03a3
7 changed files with 56 additions and 3 deletions
@@ -540,7 +540,7 @@ public final class AnnotationsHighlightUtil {
PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
if (nameReferenceElement != null) {
PsiElement resolved = nameReferenceElement.resolve();
if (!(resolved instanceof PsiClass) || !((PsiClass)resolved).isAnnotationType()) {
if (resolved != null && (!(resolved instanceof PsiClass psiClass) || !psiClass.isAnnotationType())) {
String description = JavaErrorBundle.message("annotation.annotation.type.expected");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(nameReferenceElement).descriptionAndTooltip(description);
}
@@ -211,6 +211,10 @@ public final class HighlightUtil {
boolean convertible = TypeConversionUtil.areTypesConvertible(operandType, checkType);
boolean primitiveInPatternsEnabled = PsiUtil.isAvailable(JavaFeature.PRIMITIVE_TYPES_IN_PATTERNS, expression);
if (((operandIsPrimitive || checkIsPrimitive) && !primitiveInPatternsEnabled) || !convertible) {
if (!convertible && IncompleteModelUtil.isIncompleteModel(expression) &&
IncompleteModelUtil.isPotentiallyConvertible(checkType, operand)) {
return;
}
String message = JavaErrorBundle.message("inconvertible.type.cast", JavaHighlightUtil.formatType(operandType), JavaHighlightUtil
.formatType(checkType));
HighlightInfo.Builder info =
@@ -328,6 +332,9 @@ public final class HighlightUtil {
if (operandType != null &&
!TypeConversionUtil.areTypesConvertible(operandType, castType, PsiUtil.getLanguageLevel(expression)) &&
!RedundantCastUtil.isInPolymorphicCall(expression)) {
if (IncompleteModelUtil.isIncompleteModel(expression) && IncompleteModelUtil.isPotentiallyConvertible(castType, operand)) {
return null;
}
String message = JavaErrorBundle.message("inconvertible.type.cast", JavaHighlightUtil.formatType(operandType), JavaHighlightUtil
.formatType(castType));
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message);
@@ -179,6 +179,9 @@ final class IncompleteModelUtil {
if (expression instanceof PsiReferenceExpression ref && canBePendingReference(ref)) {
return true;
}
if (expression instanceof PsiArrayAccessExpression accessExpression) {
return mayHaveUnknownTypeDueToPendingReference(accessExpression.getArrayExpression());
}
return false;
}
@@ -194,7 +197,7 @@ final class IncompleteModelUtil {
if (qualifier == null) {
PsiClass psiClass = ClassUtils.getContainingClass(ref);
while (psiClass != null) {
if (isHierarchyResolved(psiClass)) return true;
if (!isHierarchyResolved(psiClass)) return true;
psiClass = ClassUtils.getContainingClass(psiClass);
}
boolean call = ref.getParent() instanceof PsiMethodCallExpression;
@@ -221,6 +221,9 @@ final class ModuleHighlightUtil {
PsiJavaModule target = ref.resolve();
if (target == null) {
if (ref.multiResolve(true).length == 0) {
if (IncompleteModelUtil.isIncompleteModel(statement)) {
return IncompleteModelUtil.getPendingReferenceHighlightInfo(refElement);
}
String message = JavaErrorBundle.message("module.not.found", refElement.getReferenceText());
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(refElement).descriptionAndTooltip(message);
}
@@ -1,3 +1,8 @@
import java.util.Map;
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>;
public class Simple {
int test() {
test().<error descr="Cannot call method because 'test()' has primitive type int">run</error>();
@@ -37,4 +42,28 @@ public class Simple {
method(<error descr="'method(java.lang.String, java.lang.Object)' in 'Simple' cannot be applied to '(Unknown, java.lang.String)'">u</error>, "Hello");
method(<error descr="'method(java.lang.String, java.lang.Object)' in 'Simple' cannot be applied to '(Unknown, Unknown)'">u</error>, u);
}
@<info descr="Not resolved until the project is fully loaded">Anno</info>
void annotated(Map<String, @<info descr="Not resolved until the project is fully loaded">Anno</info> String> map) {}
void cast(String s, <info descr="Not resolved until the project is fully loaded">Unknown</info> u) {
<info descr="Not resolved until the project is fully loaded">Unknown2</info> u2 = (<info descr="Not resolved until the project is fully loaded">Unknown</info>)u;
String s2 = <error descr="Inconvertible types; cannot cast 'Unknown' to 'java.lang.String'">(String)u</error>;
}
void instanceOf(String s, <info descr="Not resolved until the project is fully loaded">Unknown</info> u) {
if (u instanceof <info descr="Not resolved until the project is fully loaded">Unknown2</info>) {}
if (<error descr="Inconvertible types; cannot cast 'Unknown' to 'java.lang.String'">u instanceof String</error>) {}
if (<error descr="Inconvertible types; cannot cast 'java.lang.String' to 'Unknown'">s instanceof <info descr="Not resolved until the project is fully loaded">Unknown</info></error>) {}
}
void callOnArray(<info descr="Not resolved until the project is fully loaded">Unknown</info> u) {
u.<info descr="Not resolved until the project is fully loaded">foo</info>()[0].<info descr="Not resolved until the project is fully loaded">blah</info>();
}
static class Clss implements <info descr="Not resolved until the project is fully loaded">MyInterface</info> {
void run() {
<info descr="Not resolved until the project is fully loaded">foo</info>(<info descr="Not resolved until the project is fully loaded">bar</info>);
}
}
}
@@ -0,0 +1,5 @@
<info>module</info> myModule {
<info>requires</info> <info descr="Not resolved until the project is fully loaded">my.unknown.mod</info>;
<info>exports</info> <error descr="Package not found: my.unknown.pkg">my.unknown.pkg</error>;
}
@@ -9,9 +9,13 @@ public final class IncompleteModelHighlightingTest extends LightDaemonAnalyzerTe
static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/incompleteHighlighting";
private void doTest() {
doTest(getTestName(false) + ".java");
}
private void doTest(String fileName) {
var ignored = WriteAction.compute(() -> getProject().getService(IncompleteDependenciesService.class).enterIncompleteState());
try {
doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, true);
doTest(BASE_PATH + "/" + fileName, true, true);
}
finally {
WriteAction.run(ignored::close);
@@ -19,6 +23,8 @@ public final class IncompleteModelHighlightingTest extends LightDaemonAnalyzerTe
}
public void testSimple() { doTest(); }
public void testModuleInfo() { doTest("module-info.java"); }
public void testDefaultLoaderFactory() { doTest(); }