replace with diamonds should always check if inferred type agrees with expected type (IDEA-73944)

This commit is contained in:
anna
2011-09-07 11:50:41 +02:00
parent e24044f3aa
commit 8fef5fc92d
12 changed files with 97 additions and 18 deletions

View File

@@ -86,15 +86,16 @@ public class ChangeNewOperatorTypeFix implements IntentionAction {
else {
final PsiAnonymousClass anonymousClass = originalExpression.getAnonymousClass();
newExpression = (PsiNewExpression)factory.createExpressionFromText("new " + toType.getCanonicalText() + "()" + (anonymousClass != null ? "{}" : ""), originalExpression);
PsiExpressionList argumentList = originalExpression.getArgumentList();
if (argumentList == null) return;
newExpression.getArgumentList().replace(argumentList);
if (anonymousClass == null) { //just to prevent useless inference
if (PsiDiamondTypeUtil.canCollapseToDiamond(newExpression, originalExpression, false)) {
if (PsiDiamondTypeUtil.canCollapseToDiamond(newExpression, originalExpression, toType)) {
final PsiElement paramList = PsiDiamondTypeUtil.replaceExplicitWithDiamond(newExpression.getClassOrAnonymousClassReference().getParameterList());
newExpression = PsiTreeUtil.getParentOfType(paramList, PsiNewExpression.class);
}
}
PsiExpressionList argumentList = originalExpression.getArgumentList();
if (argumentList == null) return;
newExpression.getArgumentList().replace(argumentList);
if (anonymousClass != null) {
final PsiAnonymousClass newAnonymousClass = (PsiAnonymousClass)newExpression.getAnonymousClass().replace(anonymousClass);
final PsiClass aClass = PsiUtil.resolveClassInType(toType);

View File

@@ -66,7 +66,7 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT
@Override
public void visitNewExpression(PsiNewExpression expression) {
if (PsiDiamondTypeUtil.canCollapseToDiamond(expression, expression)) {
if (PsiDiamondTypeUtil.canCollapseToDiamond(expression, expression, null)) {
final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
LOG.assertTrue(classReference != null);
final PsiReferenceParameterList parameterList = classReference.getParameterList();

View File

@@ -16,12 +16,11 @@
package com.intellij.psi.impl;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInspection.ExplicitTypeCanBeDiamondInspection;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -34,13 +33,9 @@ public class PsiDiamondTypeUtil {
private PsiDiamondTypeUtil() {
}
public static boolean canCollapseToDiamond(PsiNewExpression expression, PsiExpression context) {
return canCollapseToDiamond(expression, context, true);
}
public static boolean canCollapseToDiamond(PsiNewExpression expression,
PsiExpression context,
boolean checkAssignable) {
public static boolean canCollapseToDiamond(final PsiNewExpression expression,
final PsiNewExpression context,
final @Nullable PsiType expectedType) {
if (PsiUtil.getLanguageLevel(context).isAtLeast(LanguageLevel.JDK_1_7)) {
final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
if (classReference != null) {
@@ -49,11 +44,16 @@ public class PsiDiamondTypeUtil {
final PsiTypeElement[] typeElements = parameterList.getTypeParameterElements();
if (typeElements.length > 0) {
if (typeElements.length == 1 && typeElements[0].getType() instanceof PsiDiamondType) return false;
final PsiDiamondType.DiamondInferenceResult inferenceResult = PsiDiamondType.resolveInferredTypes(expression);
final PsiDiamondType.DiamondInferenceResult inferenceResult = PsiDiamondType.resolveInferredTypes(expression, context);
if (inferenceResult.getErrorMessage() == null) {
if (!checkAssignable) return true;
final List<PsiType> types = inferenceResult.getInferredTypes();
final PsiType[] typeArguments = parameterList.getTypeArguments();
PsiType[] typeArguments = null;
if (expectedType instanceof PsiClassType) {
typeArguments = ((PsiClassType)expectedType).getParameters();
}
if (typeArguments == null) {
typeArguments = parameterList.getTypeArguments();
}
if (types.size() == typeArguments.length) {
for (int i = 0, typeArgumentsLength = typeArguments.length; i < typeArgumentsLength; i++) {
PsiType typeArgument = typeArguments[i];

View File

@@ -749,7 +749,9 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
.createVariableDeclarationStatement("x", expectedType, initializer).getDeclaredElements()[0])
.getInitializer();
if (tryToDetectDiamondNewExpr instanceof PsiNewExpression &&
PsiDiamondTypeUtil.canCollapseToDiamond((PsiNewExpression)tryToDetectDiamondNewExpr, initializer)) {
PsiDiamondTypeUtil.canCollapseToDiamond((PsiNewExpression)tryToDetectDiamondNewExpr,
(PsiNewExpression)tryToDetectDiamondNewExpr,
expectedType)) {
final PsiElement paramList = PsiDiamondTypeUtil
.replaceExplicitWithDiamond(newExpression.getClassOrAnonymousClassReference().getParameterList());
return PsiTreeUtil.getParentOfType(paramList, PsiNewExpression.class);

View File

@@ -0,0 +1,12 @@
// "Change 'new Foo<Integer>()' to 'new Foo<Number>()'" "true"
class Foo<T> {
Foo(T t) {}
Foo() {}
}
class Constructors {
public static void main(String[] args) {
Foo<Number> foo2 = new Foo<>();
}
}

View File

@@ -0,0 +1,12 @@
// "Change 'new Foo<Integer>(...)' to 'new Foo<Number>()'" "true"
class Foo<T> {
Foo(T t) {}
Foo() {}
}
class Constructors {
public static void main(String[] args) {
Foo<Number> foo2 = new Foo<Number>(1);
}
}

View File

@@ -0,0 +1,12 @@
// "Change 'new Foo<Integer>()' to 'new Foo<Number>()'" "true"
class Foo<T> {
Foo(T t) {}
Foo() {}
}
class Constructors {
public static void main(String[] args) {
Foo<Number> foo2 = new Foo<Int<caret>eger>();
}
}

View File

@@ -0,0 +1,12 @@
// "Change 'new Foo<Integer>(...)' to 'new Foo<Number>()'" "true"
class Foo<T> {
Foo(T t) {}
Foo() {}
}
class Constructors {
public static void main(String[] args) {
Foo<Number> foo2 = new Foo<Int<caret>eger>(1);
}
}

View File

@@ -0,0 +1,10 @@
class Test {
void foo() {
final Foo<Number> a = new Foo<Number>(1);
}
}
class Foo<T> {
Foo(T t) {
}
}

View File

@@ -0,0 +1,10 @@
class Test {
void foo() {
new Foo<Num<caret>ber>(1);
}
}
class Foo<T> {
Foo(T t) {
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.daemon;
import com.intellij.codeInsight.daemon.quickFix.ChangeNewOperatorTypeTest;
import com.intellij.codeInsight.daemon.quickFix.Simplify2DiamondInspectionsTest;
import com.intellij.refactoring.*;
import junit.framework.Test;
@@ -33,6 +34,8 @@ public class DiamondSuite {
testSuite.addTestSuite(LightAdvHighlightingJdk7Test.class);
testSuite.addTestSuite(Simplify2DiamondInspectionsTest.class);
testSuite.addTestSuite(IntroduceParameterTest.class);
testSuite.addTestSuite(IntroduceVariableTest.class);
testSuite.addTestSuite(ChangeNewOperatorTypeTest.class);
return testSuite;
}
}

View File

@@ -16,6 +16,7 @@ import com.intellij.util.containers.MultiMap;
import junit.framework.Assert;
import org.jetbrains.annotations.NonNls;
import java.util.ArrayList;
import java.util.Collection;
/**
@@ -253,6 +254,10 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
doTest(new MockIntroduceVariableHandler("a", true, true, true, "java.util.ArrayList<java.lang.String>"));
}
public void testCantCollapsedToDiamond() throws Exception {
doTest(new MockIntroduceVariableHandler("a", true, true, true, "Foo<java.lang.Number>"));
}
public void testSiblingInnerClassType() throws Exception {
doTest(new MockIntroduceVariableHandler("vari", true, false, false, "A.B") {
@Override