diamonds with anonymous: reject cases according to JDK-8062373

This commit is contained in:
Anna Kozlova
2015-09-09 16:47:55 +03:00
parent 9a6264dcc0
commit 87f484a5fe
7 changed files with 110 additions and 2 deletions
@@ -26,6 +26,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.PsiConflictResolver;
@@ -133,7 +134,17 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return DiamondInferenceResult.EXPLICIT_CONSTRUCTOR_TYPE_ARGS;
}
return resolveInferredTypesNoCheck(newExpression, context);
final DiamondInferenceResult inferenceResult = resolveInferredTypesNoCheck(newExpression, context);
if (anonymousClass != null && PsiUtil.isLanguageLevel9OrHigher(newExpression)) {
final InferredAnonymTypeVisitor anonymTypeVisitor = new InferredAnonymTypeVisitor(context);
for (PsiType type : inferenceResult.getInferredTypes()) {
final Boolean accepted = type.accept(anonymTypeVisitor);
if (accepted != null && !accepted.booleanValue()) {
return PsiDiamondTypeImpl.DiamondInferenceResult.ANONYMOUS_INNER_RESULT;
}
}
}
return inferenceResult;
}
public static DiamondInferenceResult resolveInferredTypesNoCheck(final PsiNewExpression newExpression, final PsiElement context) {
@@ -457,4 +468,64 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
}
return false;
}
/**
* from JDK-8062373 Allow diamond to be used with anonymous classes
* It is a compile-time error if the superclass or superinterface type of the anonymous class, T, or any subexpression of T, has one of the following forms:
* - A type variable (4.4) that was not declared as a type parameter (such as a type variable produced by capture conversion (5.1.10))
* - An intersection type (4.9)
* - A class or interface type, where the class or interface declaration is not accessible from the class or interface in which the expression appears.
*
* The term "subexpression" includes type arguments of parameterized types (4.5), bounds of wildcards (4.5.1), and element types of array types (10.1).
* It excludes bounds of type variables.
*/
private static class InferredAnonymTypeVisitor extends PsiTypeVisitor<Boolean> {
private final PsiElement myExpression;
public InferredAnonymTypeVisitor(PsiElement expression) {
myExpression = expression;
}
@Nullable
@Override
public Boolean visitType(PsiType type) {
return true;
}
@Nullable
@Override
public Boolean visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
return false;
}
@Nullable
@Override
public Boolean visitIntersectionType(PsiIntersectionType intersectionType) {
return false;
}
@Nullable
@Override
public Boolean visitClassType(PsiClassType classType) {
final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
final PsiClass psiClass = resolveResult.getElement();
if (psiClass != null) {
if (psiClass instanceof PsiTypeParameter && InferenceSession.isFreshVariable((PsiTypeParameter)psiClass)) {
return false;
}
if (!PsiUtil.isAccessible(psiClass, myExpression, null)) {
return false;
}
for (PsiType psiType : resolveResult.getSubstitutor().getSubstitutionMap().values()) {
final Boolean accepted = psiType.accept(this);
if (accepted != null && !accepted.booleanValue()) {
return false;
}
}
}
return true;
}
}
}
@@ -1628,6 +1628,10 @@ public class InferenceSession {
final PsiElement originalContext = p1.getUserData(ORIGINAL_CONTEXT);
return originalContext != null && originalContext == p2.getUserData(ORIGINAL_CONTEXT);
}
public static boolean isFreshVariable(PsiTypeParameter typeParameter) {
return typeParameter.getUserData(ORIGINAL_CONTEXT) != null;
}
public static PsiClass findParameterizationOfTheSameGenericClass(List<PsiType> upperBounds,
Processor<Pair<PsiType, PsiType>> processor) {
@@ -47,7 +47,7 @@ public class PsiPolyExpressionUtil {
return isPolyExpression(((PsiParenthesizedExpression)expression).getExpression());
}
else if (expression instanceof PsiNewExpression) {
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)expression).getClassReference();
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)expression).getClassOrAnonymousClassReference();
if (classReference != null) {
final PsiReferenceParameterList parameterList = classReference.getParameterList();
if (parameterList != null) {
@@ -0,0 +1,6 @@
class A<T> {}
class Foo<K extends A<K>> {
{
Foo foo = new Foo<<error descr="Cannot use ''<>'' with anonymous inner classes"></error>>() {};
}
}
@@ -0,0 +1,9 @@
import java.util.List;
class Foo<E extends List<String> & Runnable> {
Foo() {}
{
Foo foo = new Foo<<error descr="Cannot use ''<>'' with anonymous inner classes"></error>>() {};
}
}
@@ -0,0 +1,15 @@
class B {
private static class A {}
public static class C extends A {}
public static class D extends A {}
}
class Foo<E> {
Foo(E e, E e1) {}
{
Foo foo = new Foo<<error descr="Cannot use ''<>'' with anonymous inner classes"></error>>(new B.C(), new B.D()) {};
}
}
@@ -49,6 +49,9 @@ public class LightAdvHighlightingJdk9Test extends LightDaemonAnalyzerTestCase {
public void testTryWithResources() { doTest(false, false); }
public void testDiamondsWithAnonymous() { doTest(false, false);}
public void testDiamondsWithAnonymousRejectInferredFreshVariables() { doTest(false, false);}
public void testDiamondsWithAnonymousRejectNotAccessibleType() { doTest(false, false);}
public void testDiamondsWithAnonymousRejectIntersectionType() { doTest(false, false);}
public void testValueTypes() { setLanguageLevel(LanguageLevel.JDK_X); doTest(false, false); }
}