redundant lambda code block: check applicability over replaced lambda

This commit is contained in:
Anna.Kozlova
2016-05-23 16:29:23 +02:00
parent 4a5ace89f3
commit 99ce4b4f46
5 changed files with 67 additions and 33 deletions
@@ -284,8 +284,8 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
.giveUniqueNames(project, elementFactory, lambdaExpression,
usedLocalNames, variables.toArray(new PsiVariable[variables.size()]));
final PsiExpression singleExpr = RedundantLambdaCodeBlockInspection.isCodeBlockRedundant(lambdaExpression,
lambdaExpression.getBody());
final PsiExpression singleExpr = RedundantLambdaCodeBlockInspection.isCodeBlockRedundant(
lambdaExpression.getBody());
if (singleExpr != null) {
lambdaExpression.getBody().replace(singleExpr);
}
@@ -20,20 +20,13 @@ import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.intention.HighPriorityAction;
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.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* User: anna
@@ -75,7 +68,7 @@ public class RedundantLambdaCodeBlockInspection extends BaseJavaBatchLocalInspec
super.visitLambdaExpression(expression);
if (PsiUtil.isLanguageLevel8OrHigher(expression)) {
final PsiElement body = expression.getBody();
final PsiExpression psiExpression = isCodeBlockRedundant(expression, body);
final PsiExpression psiExpression = isCodeBlockRedundant(body);
if (psiExpression != null) {
final PsiElement errorElement;
final PsiElement parent = psiExpression.getParent();
@@ -92,31 +85,22 @@ public class RedundantLambdaCodeBlockInspection extends BaseJavaBatchLocalInspec
};
}
public static PsiExpression isCodeBlockRedundant(PsiExpression expression, PsiElement body) {
public static PsiExpression isCodeBlockRedundant(PsiElement body) {
if (body instanceof PsiCodeBlock) {
PsiExpression psiExpression = LambdaUtil.extractSingleExpressionFromBody(body);
if (psiExpression != null && !findCommentsOutsideExpression(body, psiExpression)) {
if (LambdaUtil.isExpressionStatementExpression(psiExpression)) {
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent());
if (parent instanceof PsiExpressionList) {
final PsiElement gParent = parent.getParent();
if (gParent instanceof PsiCallExpression) {
final CandidateInfo[] candidates = PsiResolveHelper.SERVICE.getInstance(gParent.getProject())
.getReferencedMethodCandidates((PsiCallExpression)gParent, false, true);
if (candidates.length > 1) {
final List<CandidateInfo> info = new ArrayList<CandidateInfo>(Arrays.asList(candidates));
final LanguageLevel level = PsiUtil.getLanguageLevel(parent);
final JavaMethodsConflictResolver conflictResolver = new JavaMethodsConflictResolver((PsiExpressionList)parent, level);
final PsiExpressionList argumentList = ((PsiCallExpression)gParent).getArgumentList();
if (argumentList == null) {
return null;
}
final boolean atLeastOneMatchFound = conflictResolver.checkParametersNumber(info, argumentList.getExpressions().length, false);
if (!atLeastOneMatchFound) {
return null;
}
conflictResolver.checkSpecifics(info, MethodCandidateInfo.ApplicabilityLevel.VARARGS, level);
if (info.size() > 1) {
final PsiCall call = LambdaUtil.treeWalkUp(body);
if (call != null && call.resolveMethod() != null) {
final int offsetInTopCall = body.getTextRange().getStartOffset() - call.getTextRange().getStartOffset();
PsiCall copyCall = LambdaUtil.copyTopLevelCall(call);
if (copyCall == null) return null;
final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(copyCall.findElementAt(offsetInTopCall), PsiCodeBlock.class);
if (codeBlock != null) {
final PsiElement parent = codeBlock.getParent();
if (parent instanceof PsiLambdaExpression) {
codeBlock.replace(psiExpression);
if (copyCall.resolveMethod() == null || ((PsiLambdaExpression)parent).getFunctionalInterfaceType() == null) {
return null;
}
}
@@ -31,7 +31,6 @@ import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.RedundantCastUtil;
import com.intellij.refactoring.introduceField.ElementToWorkOn;
import com.intellij.refactoring.introduceVariable.IntroduceVariableHandler;
import com.intellij.util.Function;
import com.intellij.util.text.UniqueNameGenerator;
import com.siyeh.ig.psiutils.SideEffectChecker;
import org.jetbrains.annotations.NotNull;
@@ -230,7 +229,7 @@ public class LambdaRefactoringUtil {
public static void simplifyToExpressionLambda(@NotNull final PsiLambdaExpression lambdaExpression) {
final PsiElement body = lambdaExpression.getBody();
final PsiExpression singleExpression = RedundantLambdaCodeBlockInspection.isCodeBlockRedundant(lambdaExpression, body);
final PsiExpression singleExpression = RedundantLambdaCodeBlockInspection.isCodeBlockRedundant(body);
if (singleExpression != null) {
body.replace(singleExpression);
}
@@ -0,0 +1,23 @@
// "Replace with lambda" "true"
import java.util.Collection;
import java.util.function.Function;
class Test {
public static <T, V> V[] map2Array( T[] array, Class<? super V> aClass, Function<T, V> mapper) {
return null;
}
public static <T, V> V[] map2Array(Collection<T> array, Class<? super V> aClass, Function<T, V> mapper) {
return null;
}
void m(String[] f, int i, FooBar manager){
map2Array(f, Integer.class, (NullableFunction<String, Integer>) s -> s.length());
}
interface NullableFunction<A, B> extends Function<A, B> {
B apply(final A param);
}
}
@@ -0,0 +1,28 @@
// "Replace with lambda" "true"
import java.util.Collection;
import java.util.function.Function;
class Test {
public static <T, V> V[] map2Array( T[] array, Class<? super V> aClass, Function<T, V> mapper) {
return null;
}
public static <T, V> V[] map2Array(Collection<T> array, Class<? super V> aClass, Function<T, V> mapper) {
return null;
}
void m(String[] f, int i, FooBar manager){
map2Array(f, Integer.class, new Nullable<caret>Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
});
}
interface NullableFunction<A, B> extends Function<A, B> {
B apply(final A param);
}
}