anonymous -> lambda: cast if overload would fail (IDEA-144372)

This commit is contained in:
Anna Kozlova
2015-08-27 11:19:30 +03:00
parent e0b484f910
commit ad99c2d9b5
7 changed files with 71 additions and 65 deletions
@@ -206,7 +206,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
return false;
}
public static PsiLambdaExpression replacePsiElementWithLambda(@NotNull PsiElement element, final boolean ignoreEqualsMethod) {
public static PsiExpression replacePsiElementWithLambda(@NotNull PsiElement element, final boolean ignoreEqualsMethod) {
if (element instanceof PsiNewExpression) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return null;
final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass();
@@ -215,7 +215,6 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
ChangeContextUtil.encodeContextInfo(anonymousClass, true);
final PsiElement lambdaContext = anonymousClass.getParent().getParent();
boolean validContext = LambdaUtil.isValidLambdaContext(lambdaContext);
final String canonicalText = anonymousClass.getBaseClassType().getCanonicalText();
final PsiMethod method;
@@ -254,8 +253,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
ReplaceWithLambdaFix
.giveUniqueNames(project, anonymousClass, elementFactory, body, conflictingLocals.toArray(new PsiVariable[conflictingLocals.size()]));
final String lambdaWithTypesDeclared = ReplaceWithLambdaFix.composeLambdaText(method, true);
final String withoutTypesDeclared = ReplaceWithLambdaFix.composeLambdaText(method, false);
final String withoutTypesDeclared = ReplaceWithLambdaFix.composeLambdaText(method);
PsiLambdaExpression lambdaExpression =
(PsiLambdaExpression)elementFactory.createExpressionFromText(withoutTypesDeclared, anonymousClass);
@@ -275,47 +273,24 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
lambdaExpression.getBody().replace(singleExpr);
}
ChangeContextUtil.decodeContextInfo(lambdaExpression, null, null);
if (!validContext) {
final PsiParenthesizedExpression typeCast =
(PsiParenthesizedExpression)elementFactory.createExpressionFromText("((" + canonicalText + ")" + withoutTypesDeclared + ")", lambdaExpression);
final PsiExpression typeCastExpr = typeCast.getExpression();
LOG.assertTrue(typeCastExpr != null);
final PsiExpression typeCastOperand = ((PsiTypeCastExpression)typeCastExpr).getOperand();
LOG.assertTrue(typeCastOperand != null);
final PsiElement fromText = ((PsiLambdaExpression)typeCastOperand).getBody();
LOG.assertTrue(fromText != null);
lambdaBody = lambdaExpression.getBody();
LOG.assertTrue(lambdaBody != null);
fromText.replace(lambdaBody);
lambdaExpression.replace(typeCast);
return lambdaExpression;
}
PsiType interfaceType = lambdaExpression.getFunctionalInterfaceType();
if (ReplaceWithLambdaFix.isInferred(lambdaExpression, interfaceType)) {
final PsiLambdaExpression withTypes =
(PsiLambdaExpression)elementFactory.createExpressionFromText(lambdaWithTypesDeclared, lambdaExpression);
final PsiElement withTypesBody = withTypes.getBody();
LOG.assertTrue(withTypesBody != null);
lambdaBody = lambdaExpression.getBody();
LOG.assertTrue(lambdaBody != null);
withTypesBody.replace(lambdaBody);
lambdaExpression = (PsiLambdaExpression)lambdaExpression.replace(withTypes);
interfaceType = lambdaExpression.getFunctionalInterfaceType();
if (ReplaceWithLambdaFix.isInferred(lambdaExpression, interfaceType)) {
final PsiTypeCastExpression typeCast = (PsiTypeCastExpression)elementFactory.createExpressionFromText("(" + canonicalText + ")" + withoutTypesDeclared, lambdaExpression);
final PsiExpression typeCastOperand = typeCast.getOperand();
LOG.assertTrue(typeCastOperand instanceof PsiLambdaExpression);
final PsiElement fromText = ((PsiLambdaExpression)typeCastOperand).getBody();
LOG.assertTrue(fromText != null);
lambdaBody = lambdaExpression.getBody();
LOG.assertTrue(lambdaBody != null);
fromText.replace(lambdaBody);
lambdaExpression.replace(typeCast);
}
PsiTypeCastExpression typeCast = (PsiTypeCastExpression)elementFactory
.createExpressionFromText("(" + canonicalText + ")" + withoutTypesDeclared, lambdaExpression);
final PsiExpression typeCastOperand = typeCast.getOperand();
LOG.assertTrue(typeCastOperand instanceof PsiLambdaExpression);
final PsiElement fromText = ((PsiLambdaExpression)typeCastOperand).getBody();
LOG.assertTrue(fromText != null);
lambdaBody = lambdaExpression.getBody();
LOG.assertTrue(lambdaBody != null);
fromText.replace(lambdaBody);
((PsiLambdaExpression)typeCastOperand).getParameterList().replace(lambdaExpression.getParameterList());
typeCast = (PsiTypeCastExpression)lambdaExpression.replace(typeCast);
if (RedundantCastUtil.isCastRedundant(typeCast)) {
final PsiExpression operand = typeCast.getOperand();
LOG.assertTrue(operand != null);
return (PsiExpression)typeCast.replace(operand);
}
return lambdaExpression;
return (PsiExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(typeCast);
}
return null;
}
@@ -385,45 +360,32 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
}
}
private static boolean isInferred(PsiLambdaExpression lambdaExpression, PsiType interfaceType) {
return interfaceType == null || !LambdaUtil.isLambdaFullyInferred(lambdaExpression, interfaceType) || !LambdaUtil.isFunctionalType(interfaceType);
}
private static String composeLambdaText(PsiMethod method, final boolean appendType) {
private static String composeLambdaText(PsiMethod method) {
final StringBuilder buf = new StringBuilder();
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length != 1 || appendType) {
if (parameters.length != 1) {
buf.append("(");
}
buf.append(StringUtil.join(parameters,
new Function<PsiParameter, String>() {
@Override
public String fun(PsiParameter parameter) {
return composeParameter(parameter, appendType);
return composeParameter(parameter);
}
}, ","));
if (parameters.length != 1 || appendType) {
if (parameters.length != 1) {
buf.append(")");
}
buf.append("-> {}");
return buf.toString();
}
private static String composeParameter(PsiParameter parameter,
boolean appendType) {
final String parameterType;
if (appendType) {
final PsiTypeElement typeElement = parameter.getTypeElement();
parameterType = typeElement != null ? (typeElement.getText() + " ") : "";
}
else {
parameterType = "";
}
private static String composeParameter(PsiParameter parameter) {
String parameterName = parameter.getName();
if (parameterName == null) {
parameterName = "";
}
return parameterType + parameterName;
return parameterName;
}
}
@@ -56,7 +56,7 @@ public class GuavaFunctionAndPredicateConverter {
if (expression instanceof PsiNewExpression) {
final PsiAnonymousClass anonymousClass = ((PsiNewExpression)expression).getAnonymousClass();
if (anonymousClass != null && AnonymousCanBeLambdaInspection.canBeConvertedToLambda(anonymousClass, true)) {
final PsiLambdaExpression lambdaExpression = AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true);
final PsiExpression lambdaExpression = AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true);
LOG.assertTrue(lambdaExpression != null);
return lambdaExpression.getText();
}
@@ -157,6 +157,17 @@ public class RedundantCastUtil {
super.visitAssignmentExpression(expression);
}
@Override
public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
PsiType type = expression.getType();
if (type instanceof PsiArrayType) {
for (PsiExpression initializer : expression.getInitializers()) {
processPossibleTypeCast(initializer, ((PsiArrayType)type).getComponentType());
}
}
super.visitArrayInitializerExpression(expression);
}
@Override public void visitVariable(PsiVariable variable) {
processPossibleTypeCast(variable.getInitializer(), variable.getType());
super.visitVariable(variable);
@@ -2,7 +2,7 @@
class Test {
{
((Runnable) () -> {
}).getClass();;
}
}
@@ -9,6 +9,6 @@ class Test2 {
static <T> I<T> bar(I<T> i){return i;}
{
bar(list -> null);
bar((I<String>) list -> null);
}
}
@@ -0,0 +1,14 @@
// "Replace with lambda" "true"
import java.util.concurrent.Callable;
class A {
static void submit(Runnable r){}
static <T> T submit(Callable<T> c){
return null;
}
public static void main(String[] args) {
submit((Runnable) () -> new A());
}
}
@@ -0,0 +1,19 @@
// "Replace with lambda" "true"
import java.util.concurrent.Callable;
class A {
static void submit(Runnable r){}
static <T> T submit(Callable<T> c){
return null;
}
public static void main(String[] args) {
submit(new Run<caret>nable() {
@Override
public void run() {
new A();
}
});
}
}