[java] Basic support for external type annotations

Only in XML directly; no editing UI for now; no inlays for now; only for libraries (Cls), currently no intent to extend to sources (Psi)
Part of IDEA-231901 Support TYPE_USE in external annotations

GitOrigin-RevId: 672ed09f57ffc40b61e8fe4dd33d0f9acdac92dc
This commit is contained in:
Tagir Valeev
2024-09-18 18:47:00 +02:00
committed by intellij-monorepo-bot
parent 1c8240ecd6
commit b50767f679
20 changed files with 824 additions and 506 deletions

View File

@@ -11,10 +11,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiFileEx;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiFormatUtilBase;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.util.*;
import com.intellij.util.JavaPsiConstructorUtil;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.Nls;
@@ -86,7 +83,7 @@ public final class JavaHighlightUtil {
@NotNull
public static String formatType(@Nullable PsiType type) {
return type == null ? PsiKeyword.NULL : type.getInternalCanonicalText();
return type == null ? PsiKeyword.NULL : PsiTypesUtil.removeExternalAnnotations(type).getInternalCanonicalText();
}
@Nullable

View File

@@ -41,7 +41,6 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.NullableFunction;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.JBIterable;
import com.intellij.util.containers.MultiMap;
@@ -280,16 +279,12 @@ public final class DfaPsiUtil {
*/
@NotNull
public static Nullability getFunctionalParameterNullability(PsiFunctionalExpression function, int index) {
Nullability nullability = inferLambdaParameterNullability(function, index);
if(nullability != Nullability.UNKNOWN) {
return nullability;
}
PsiClassType type = ObjectUtils.tryCast(LambdaUtil.getFunctionalInterfaceType(function, true), PsiClassType.class);
PsiClassType type = tryCast(LambdaUtil.getFunctionalInterfaceType(function, true), PsiClassType.class);
PsiMethod sam = LambdaUtil.getFunctionalInterfaceMethod(type);
if (sam != null) {
PsiParameter parameter = sam.getParameterList().getParameter(index);
if (parameter != null) {
nullability = getElementNullability(null, parameter);
Nullability nullability = getElementNullability(null, parameter);
if (nullability != Nullability.UNKNOWN) {
return nullability;
}
@@ -300,44 +295,6 @@ public final class DfaPsiUtil {
return Nullability.UNKNOWN;
}
@NotNull
private static Nullability inferLambdaParameterNullability(PsiFunctionalExpression lambda, int parameterIndex) {
PsiElement expression = lambda;
PsiElement expressionParent = lambda.getParent();
while(expressionParent instanceof PsiConditionalExpression || expressionParent instanceof PsiParenthesizedExpression) {
expression = expressionParent;
expressionParent = expressionParent.getParent();
}
if (expressionParent instanceof PsiExpressionList list && list.getParent() instanceof PsiMethodCallExpression call) {
PsiMethod method = call.resolveMethod();
if (method != null) {
int expressionIndex = ArrayUtil.find(list.getExpressions(), expression);
return getLambdaParameterNullability(method, expressionIndex, parameterIndex);
}
}
return Nullability.UNKNOWN;
}
private static final CallMatcher OPTIONAL_FUNCTIONS =
CallMatcher.instanceCall(JAVA_UTIL_OPTIONAL, "map", "filter", "ifPresent", "flatMap", "ifPresentOrElse");
private static final CallMatcher MAP_COMPUTE =
CallMatcher.instanceCall(JAVA_UTIL_MAP, "compute").parameterTypes("K", JAVA_UTIL_FUNCTION_BI_FUNCTION);
@NotNull
private static Nullability getLambdaParameterNullability(@NotNull PsiMethod method, int parameterIndex, int lambdaParameterIndex) {
if (OPTIONAL_FUNCTIONS.methodMatches(method)) {
if (parameterIndex == 0 && lambdaParameterIndex == 0) {
return Nullability.NOT_NULL;
}
}
else if (MAP_COMPUTE.methodMatches(method)) {
if (parameterIndex == 1 && lambdaParameterIndex == 1) {
return Nullability.NULLABLE;
}
}
return Nullability.UNKNOWN;
}
private static boolean isEnumPredefinedMethod(PsiMethod method) {
return CallMatcher.enumValueOf().methodMatches(method) || CallMatcher.enumValues().methodMatches(method);
}