[java-psi] IDEA-377693 Support unbounded wildcards

New exceptions are added with a discussion opened in JSpecify tracker:
https://github.com/jspecify/jspecify/issues/771

GitOrigin-RevId: ebcd3cfb99fc26e8b18c4c4ab25b10ed74ca8c11
This commit is contained in:
Tagir Valeev
2025-09-30 08:46:32 +00:00
committed by intellij-monorepo-bot
parent 0afc6f7842
commit f6b49100b4
9 changed files with 74 additions and 18 deletions
@@ -92,6 +92,11 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement
return null;
}
}
@Override
public boolean isUnboundedWildcard() {
return myVariance == VARIANCE_INVARIANT;
}
public String getCanonicalText() {
return decorateTypeText(myTypeText);
@@ -1,6 +1,8 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.impl.source;
import com.intellij.codeInsight.NullabilityAnnotationInfo;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.RecursionGuard;
@@ -49,6 +51,11 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
return CachedValuesManager.getProjectPsiDependentCache(this, __ -> calculateType());
}
@Override
public boolean isUnboundedWildcard() {
return PsiUtil.isJavaToken(getLastChild(), JavaTokenType.QUEST);
}
private @NotNull PsiType calculateType() {
PsiType inferredType = PsiAugmentProvider.getInferredType(this);
if (inferredType != null) {
@@ -118,6 +125,17 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
type = PsiWildcardType.createUnbounded(getManager());
}
type = type.annotate(createProvider(annotations));
if (isUnboundedWildcard()) {
// For bounded wildcard, nullability is defined by the bound.
// For unbounded, however, the context default annotation may affect the nullability, so we have to take this into account.
NullableNotNullManager manager = NullableNotNullManager.getInstance(getProject());
if (manager != null) {
NullabilityAnnotationInfo nullability = manager.findDefaultTypeUseNullability(this);
if (nullability != null) {
type = type.withNullability(nullability.toTypeNullability());
}
}
}
break;
}
else {