Java: better error reporting and quick fixes for the diamond operator and generic array creation (IDEA-299195)

GitOrigin-RevId: baa354ad9132bf6d939f19ecd2cfd6cfc56466a2
This commit is contained in:
Bas Leijdekkers
2024-01-08 17:34:42 +00:00
committed by intellij-monorepo-bot
parent 7e1c830a1a
commit ab928055bb
12 changed files with 78 additions and 35 deletions
@@ -165,7 +165,7 @@ public final class GenericsHighlightUtil {
PsiElement grandParent = referenceParameterList.getParent().getParent();
if (grandParent instanceof PsiTypeElement) {
PsiElement variable = grandParent.getParent();
PsiElement variable = PsiTreeUtil.skipParentsOfType(grandParent, PsiTypeElement.class);
if (variable instanceof PsiVariable) {
if (targetParametersNum == 0) {
IntentionAction action = PriorityIntentionActionWrapper
@@ -748,6 +748,19 @@ public final class GenericsHighlightUtil {
return info;
}
static HighlightInfo.Builder checkDiamondTypeNotAllowed(@NotNull PsiNewExpression expression) {
PsiReferenceParameterList typeArgumentList = expression.getTypeArgumentList();
PsiTypeElement[] typeParameterElements = typeArgumentList.getTypeParameterElements();
if (typeParameterElements.length == 1 && typeParameterElements[0].getType() instanceof PsiDiamondType) {
String description = JavaErrorBundle.message("diamond.operator.not.allowed.here");
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeArgumentList).descriptionAndTooltip(description);
info.registerFix(QuickFixFactory.getInstance().createDeleteFix(typeArgumentList), null, null, null, null);
return info;
}
return null;
}
static HighlightInfo.Builder checkTypeParameterInstantiation(@NotNull PsiNewExpression expression) {
PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
if (classReference == null) return null;
@@ -920,15 +933,14 @@ public final class GenericsHighlightUtil {
public static HighlightInfo.Builder checkGenericArrayCreation(@NotNull PsiElement element, @Nullable PsiType type) {
if (type instanceof PsiArrayType arrayType) {
if (!JavaGenericsUtil.isReifiableType(arrayType.getComponentType())) {
String description = JavaErrorBundle.message("generic.array.creation");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description);
}
if (element instanceof PsiNewExpression newExpression) {
if (newExpression.getTypeArguments().length > 0) {
PsiReferenceParameterList typeArgumentList = newExpression.getTypeArgumentList();
if (typeArgumentList.getTypeArgumentCount() > 0) {
String description = JavaErrorBundle.message("array.creation.with.type.arguments");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description);
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeArgumentList).descriptionAndTooltip(description);
info.registerFix(QuickFixFactory.getInstance().createDeleteFix(typeArgumentList), null, null, null, null);
return info;
}
PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
if (classReference != null) {
@@ -937,11 +949,37 @@ public final class GenericsHighlightUtil {
PsiTypeElement[] typeParameterElements = parameterList.getTypeParameterElements();
if (typeParameterElements.length == 1 && typeParameterElements[0].getType() instanceof PsiDiamondType) {
String description = JavaErrorBundle.message("cannot.create.array.with.empty.diamond");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description);
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameterList).descriptionAndTooltip(description);
info.registerFix(QuickFixFactory.getInstance().createDeleteFix(parameterList), null, null, null, null);
return info;
}
if (typeParameterElements.length >= 1 && !JavaGenericsUtil.isReifiableType(arrayType.getComponentType())) {
String description = JavaErrorBundle.message("generic.array.creation");
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameterList).descriptionAndTooltip(description);
info.registerFix(QuickFixFactory.getInstance().createDeleteFix(parameterList), null, null, null, null);
return info;
}
}
}
}
if (!JavaGenericsUtil.isReifiableType(arrayType.getComponentType())) {
String description = JavaErrorBundle.message("generic.array.creation");
if (element.getParent() instanceof PsiMethodReferenceExpression && element.getFirstChild() instanceof PsiTypeElement typeElement) {
PsiJavaCodeReferenceElement referenceElement = PsiTreeUtil.findChildOfType(typeElement, PsiJavaCodeReferenceElement.class);
if (referenceElement != null) {
PsiReferenceParameterList parameterList = referenceElement.getParameterList();
if (parameterList != null && parameterList.getTypeArgumentCount() > 0) {
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameterList).descriptionAndTooltip(description);
info.registerFix(QuickFixFactory.getInstance().createDeleteFix(parameterList), null, null, null, null);
return info;
}
}
}
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description);
}
}
return null;
@@ -1252,7 +1252,11 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!hasErrorResults()) add(HighlightClassUtil.checkExtendsDuplicate(ref, resolved, myFile));
if (!hasErrorResults()) add(HighlightClassUtil.checkClassExtendsForeignInnerClass(ref, resolved));
if (!hasErrorResults()) add(GenericsHighlightUtil.checkSelectStaticClassFromParameterizedType(resolved, ref));
if (!hasErrorResults()) {
if (!hasErrorResults() && parent instanceof PsiNewExpression newExpression) {
add(GenericsHighlightUtil.checkDiamondTypeNotAllowed(newExpression));
}
if (!hasErrorResults() && (!(parent instanceof PsiNewExpression newExpression) ||
newExpression.getArrayDimensions().length == 0 && newExpression.getArrayInitializer() == null)) {
add(GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, ref, result.getSubstitutor(), myJavaSdkVersion));
}
@@ -69,9 +69,10 @@ generics.reference.parameters.not.allowed=Reference parameters are not allowed h
foreach.not.applicable=Foreach not applicable to type ''{0}''
illegal.to.access.static.member.from.enum.constructor.or.instance.initializer=Accessing {0, choice, 1#static field|2#enum constant} from enum {1, choice, 1#constructor|2#instance field initializer|3#instance initializer} is not allowed
enum.types.cannot.be.instantiated=Enum types cannot be instantiated
generic.array.creation=Generic array creation
cannot.create.array.with.empty.diamond=Cannot create array with '<>'
array.creation.with.type.arguments=Cannot create array with type arguments
generic.array.creation=Generic array creation not allowed
cannot.create.array.with.empty.diamond=Array creation with '<>' not allowed
array.creation.with.type.arguments=Array creation with type arguments not allowed
diamond.operator.not.allowed.here=Diamond operator is not allowed here
generics.enum.may.not.have.type.parameters=Enum may not have type parameters
generics.annotation.members.may.not.have.type.parameters=@interface members may not have type parameters
annotation.may.not.have.type.parameters=@interface may not have type parameters
@@ -2,7 +2,7 @@ import java.util.Map;
class Test {
void baz(){
bar(<error descr="Generic array creation">new Map<?, Integer>[3]</error>);
bar(new Map<error descr="Generic array creation not allowed"><?, Integer></error>[3]);
}
void bar(Map<?, Integer> ... x){ }
@@ -2,7 +2,7 @@ import java.util.ArrayList;
class Test {
void foo() {
ArrayList<String>[] lists1 = <error descr="Cannot create array with '<>'">new ArrayList<>[5]</error>;
ArrayList<String>[] lists2 = <error descr="Cannot create array with '<>'">new ArrayList</*blah blah blah*/>[5]</error>;
ArrayList<String>[] lists1 = new ArrayList<error descr="Array creation with '<>' not allowed"><></error>[5];
ArrayList<String>[] lists2 = new ArrayList<error descr="Array creation with '<>' not allowed"></*blah blah blah*/></error>[5];
}
}
@@ -3,6 +3,6 @@ class A<T> {
}
class C<T> extends A<T> {
{
B[] o = <error descr="Generic array creation">{}</error>;
B[] o = <error descr="Generic array creation not allowed">{}</error>;
}
}
@@ -64,12 +64,12 @@ abstract class GenericTest3 implements DummyList<<error descr="No wildcard expec
<T> void foo () {}
void bar () {
this.<DummyList<? extends DummyList>>foo();
DummyList<DummyList<? super String>>[] l = <error descr="Generic array creation">new DummyList<DummyList<? super String>>[0]</error>;
DummyList<String>[] l1 = <error descr="Generic array creation">{}</error>;
DummyList<DummyList<? super String>>[] l = new DummyList<error descr="Generic array creation not allowed"><DummyList<? super String>></error>[0];
DummyList<String>[] l1 = <error descr="Generic array creation not allowed">{}</error>;
}
public <T> T[] getComponents (Class<T> baseInterfaceClass) {
T[] ts = <error descr="Generic array creation">{}</error>;
T[] ts = <error descr="Generic array creation not allowed">{}</error>;
return ts;
}
@@ -141,7 +141,7 @@ class ClassLiteral<T> {
}
class Outer<E> {
final Inner[] i = <error descr="Generic array creation">new Inner[10]</error>;
final Inner[] i = <error descr="Generic array creation not allowed">new Inner[10]</error>;
class Inner {
}
}
@@ -153,6 +153,6 @@ class Outer1<E> {
class TypeArgOnNewArray {
{
final int[] ints = <error descr="Cannot create array with type arguments">new <String>int[10]</error>;
final int[] ints = new <error descr="Array creation with type arguments not allowed"><String></error>int[10];
}
}
@@ -2,7 +2,7 @@ class B<T> {
Object[] foo(Object obj) {
class C {}
return <error descr="Generic array creation">new C[0]</error>;
return <error descr="Generic array creation not allowed">new C[0]</error>;
}
@@ -27,7 +27,7 @@ class B<T> {
I<Object> i = new I<Object>() {
class InsideAnno {}
{
InsideAnno[] array = <error descr="Generic array creation">new InsideAnno[1]</error>;
InsideAnno[] array = <error descr="Generic array creation not allowed">new InsideAnno[1]</error>;
}
};
}
@@ -48,7 +48,7 @@ class B<T> {
class O {}
{
O[] array = <error descr="Generic array creation">new O[1]</error>;
O[] array = <error descr="Generic array creation not allowed">new O[1]</error>;
}
}
};
@@ -64,12 +64,12 @@ abstract class GenericTest3 implements DummyList<<error descr="No wildcard expec
<T> void foo () {}
void bar () {
this.<DummyList<? extends DummyList>>foo();
DummyList<DummyList<? super String>>[] l = <error descr="Generic array creation">new DummyList<DummyList<? super String>>[0]</error>;
DummyList<String>[] l1 = <error descr="Generic array creation">{}</error>;
DummyList<DummyList<? super String>>[] l = new DummyList<error descr="Generic array creation not allowed"><DummyList<? super String>></error>[0];
DummyList<String>[] l1 = <error descr="Generic array creation not allowed">{}</error>;
}
public <T> T[] getComponents (Class<T> baseInterfaceClass) {
T[] ts = <error descr="Generic array creation">{}</error>;
T[] ts = <error descr="Generic array creation not allowed">{}</error>;
return ts;
}
@@ -141,7 +141,7 @@ class ClassLiteral<T> {
}
class Outer<E> {
final Inner[] i = <error descr="Generic array creation">new Inner[10]</error>;
final Inner[] i = <error descr="Generic array creation not allowed">new Inner[10]</error>;
class Inner {
}
}
@@ -40,7 +40,7 @@ class OnArrayTest {
ArrayReturnType<String[]> a3 = <error descr="Bad return type in method reference: cannot convert int[] to java.lang.String[]">int[]::new</error>;
ObjectArrayReturnType a4 = Foo<?>[]::new;
ObjectArrayReturnType a5 = <error descr="Generic array creation">Foo<? extends String>[]</error>::new;
ObjectArrayReturnType a5 = Foo<error descr="Generic array creation not allowed"><? extends String></error>[]::new;
}
}
@@ -3,16 +3,16 @@ class Main<T> {
{
I<Main<String> > aNew = Main[]::new;
I<Main<?> > aNew1 = Main<?>[]::new;
I<Main<? extends String>> aNew2 = <error descr="Generic array creation">Main<? extends String>[]</error>::new;
I<Main<? extends String>> aNew2 = Main<error descr="Generic array creation not allowed"><? extends String></error>[]::new;
I<int[]> p = int[][]::new;
I<Main<String>[]> a = Main[][]::new;
I<Main<?>[]> a1 = Main<?>[][]::new;
I<Main<? extends String>[]> a2 = <error descr="Generic array creation">Main<? extends String>[][]</error>::new;
I<Main<? extends String>[]> a2 = Main<error descr="Generic array creation not allowed"><? extends String></error>[][]::new;
I<Inner<String>> inn1 = Main.Inner[]::new;
I<Main<?>.Inner<?>> inn2 = Main<?>.Inner<?>[]::new;
I<Main<String>.Inner<String>> inn3 = <error descr="Generic array creation">Main<String>.Inner<String>[]</error>::new;
I<Main<String>.Inner<String>> inn3 = Main<String>.Inner<error descr="Generic array creation not allowed"><String></error>[]::new;
I<Main<?>.Inner<?>> inn4 = Main<?>.Inner<?>[]::<String>new;
}
@@ -10,8 +10,8 @@ class Test {
I i2 = <error descr="Unexpected wildcard">Foo<? extends String></error>::new;
I i3 = Foo<String>::new;
I i4 = <error descr="Generic array creation">Foo<? extends String>[]</error>::new;
I i5 = <error descr="Generic array creation">Foo<String>[]</error>::new;
I i4 = Foo<error descr="Generic array creation not allowed"><? extends String></error>[]::new;
I i5 = Foo<error descr="Generic array creation not allowed"><String></error>[]::new;
}
}