use lambda to avoid context remapping (IDEA-185448)

for anonymous class this expressions have to be encoded to point to outer class, for lambda expressions there is no need for that. Leave unchanged (array initializer) for old java versions
This commit is contained in:
Anna Kozlova
2018-01-30 19:21:17 +03:00
parent d8f37a3ea8
commit f1536bb969
3 changed files with 35 additions and 14 deletions

View File

@@ -4,7 +4,6 @@
package com.intellij.psi;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.RecursionGuard;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.openapi.util.registry.Registry;
@@ -17,7 +16,6 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.Producer;
import com.intellij.util.containers.ContainerUtil;
import java.util.HashMap;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -980,18 +978,29 @@ public class LambdaUtil {
}
public static PsiElement copyWithExpectedType(PsiElement expression, PsiType type) {
final String objectWithMethod = "new Object() { " + type.getCanonicalText() + " get(){ return x;}}";
final Project project = expression.getProject();
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
PsiNewExpression newExpr = (PsiNewExpression)elementFactory.createExpressionFromText(objectWithMethod, expression);
String canonicalText = type.getCanonicalText();
if (!PsiUtil.isLanguageLevel8OrHigher(expression)) {
final String arrayInitializer = "new " + canonicalText + "[]{0}";
PsiNewExpression newExpr = (PsiNewExpression)createExpressionFromText(arrayInitializer, expression);
final PsiArrayInitializerExpression initializer = newExpr.getArrayInitializer();
LOG.assertTrue(initializer != null);
return initializer.getInitializers()[0].replace(expression);
}
final String callableWithExpectedType = "(java.util.concurrent.Callable<" + canonicalText + ">)() -> x";
PsiTypeCastExpression typeCastExpr = (PsiTypeCastExpression)createExpressionFromText(callableWithExpectedType, expression);
PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)typeCastExpr.getOperand();
LOG.assertTrue(lambdaExpression != null);
PsiElement body = lambdaExpression.getBody();
LOG.assertTrue(body instanceof PsiExpression);
return body.replace(expression);
}
private static PsiExpression createExpressionFromText(String exprText, PsiElement context) {
PsiExpression expr = JavaPsiFacade.getInstance(context.getProject())
.getElementFactory()
.createExpressionFromText(exprText, context);
//ensure refs to inner classes are collapsed to avoid raw types (container type would be raw in qualified text)
newExpr = (PsiNewExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(newExpr);
PsiAnonymousClass anonymousClass = newExpr.getAnonymousClass();
LOG.assertTrue(anonymousClass != null);
PsiCodeBlock body = anonymousClass.getMethods()[0].getBody();
LOG.assertTrue(body != null);
PsiExpression returnValue = ((PsiReturnStatement)body.getStatements()[0]).getReturnValue();
LOG.assertTrue(returnValue != null);
return returnValue.replace(expression);
return (PsiExpression)JavaCodeStyleManager.getInstance(context.getProject()).shortenClassReferences(expr);
}
}

View File

@@ -0,0 +1,11 @@
import java.util.*;
class Test {
private final Collection<Integer> collection = new ArrayList<>();
{
List<Integer> l = Collections.unmodifiableList((List<Integer>)this.collection);
System.out.println(l);
}
}

View File

@@ -36,6 +36,7 @@ public class LambdaRedundantCastTest extends LightDaemonAnalyzerTestCase {
public void testSer() { doTest(); }
public void testLambdaReturnExpressions() { doTest(); }
public void testLambdaReturnExpressions1() { doTest(); }
public void testPreserveThisContext() { doTest(); }
public void testPreventBadReturnTypeInReturnExpression() { doTest(); }
public void testExpectedTypeByNestedArrayInitializer() { doTest(); }
public void testCastToPrimitive() {