anonym -> lambda: disable if target SAM type is raw and methods are called on params with Object erasure (IDEA-125613)

This commit is contained in:
Anna Kozlova
2014-05-29 19:53:12 +04:00
parent 032faad977
commit 41b974e36f
2 changed files with 85 additions and 0 deletions

View File

@@ -30,9 +30,13 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.controlFlow.AnalysisCanceledException;
import com.intellij.psi.controlFlow.ControlFlow;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.hash.LinkedHashMap;
@@ -106,6 +110,43 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
};
}
private static PsiType getInferredType(PsiAnonymousClass aClass) {
final PsiExpression expression = (PsiExpression)aClass.getParent();
final PsiType psiType = PsiTypesUtil.getExpectedTypeByParent(expression);
if (psiType != null) {
return psiType;
}
PsiExpression topExpr = expression;
while (topExpr.getParent() instanceof PsiParenthesizedExpression) {
topExpr = (PsiExpression)topExpr.getParent();
}
final PsiElement parent = topExpr.getParent();
if (parent instanceof PsiExpressionList) {
PsiExpressionList expressionList = (PsiExpressionList)parent;
final PsiElement callExpr = expressionList.getParent();
if (callExpr instanceof PsiCallExpression) {
final JavaResolveResult result = ((PsiCallExpression)callExpr).resolveMethodGenerics();
if (result instanceof MethodCandidateInfo) {
final PsiMethod method = ((MethodCandidateInfo)result).getElement();
PsiExpression[] expressions = expressionList.getExpressions();
int i = ArrayUtilRt.find(expressions, topExpr);
if (i < 0) return null;
expressions[i] = null;
final PsiParameter[] parameters = method.getParameterList().getParameters();
final PsiSubstitutor substitutor = PsiResolveHelper.SERVICE.getInstance(aClass.getProject())
.inferTypeArguments(method.getTypeParameters(), parameters, expressions,
((MethodCandidateInfo)result).getSiteSubstitutor(), callExpr.getParent(),
DefaultParameterTypeInferencePolicy.INSTANCE);
return substitutor.substitute(parameters[i].getType());
}
}
}
return null;
}
private static class ReplaceWithLambdaFix implements LocalQuickFix, HighPriorityAction {
@NotNull
@Override
@@ -328,10 +369,14 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
private final PsiMethod myMethod;
private final PsiAnonymousClass myAnonymClass;
private final boolean myRawType;
public ForbiddenRefsChecker(PsiMethod method,
PsiAnonymousClass aClass) {
myMethod = method;
myAnonymClass = aClass;
final PsiType inferredType = getInferredType(aClass);
myRawType = inferredType instanceof PsiClassType && ((PsiClassType)inferredType).isRaw();
}
@Override
@@ -390,6 +435,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
if (initializer == null ||
initializer.getTextOffset() > myAnonymClass.getTextOffset() && !((PsiField)resolved).hasModifierProperty(PsiModifier.STATIC)) {
myBodyContainsForbiddenRefs = true;
return;
}
}
} else {
@@ -407,16 +453,31 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
final Collection<PsiVariable> writtenVariables = ControlFlowUtil.getWrittenVariables(flow, 0, startOffset, false);
if (!writtenVariables.contains(resolved)) {
myBodyContainsForbiddenRefs = true;
return;
}
}
}
catch (AnalysisCanceledException e) {
myBodyContainsForbiddenRefs = true;
return;
}
}
}
}
}
if (myRawType) {
final PsiElement resolved = expression.resolve();
if (resolved instanceof PsiParameter && ((PsiParameter)resolved).getDeclarationScope() == myMethod) {
final int parameterIndex = myMethod.getParameterList().getParameterIndex((PsiParameter)resolved);
for (PsiMethod superMethod : myMethod.findDeepestSuperMethods()) {
if (PsiUtil.resolveClassInType(superMethod.getParameterList().getParameters()[parameterIndex].getType()) instanceof PsiTypeParameter) {
myBodyContainsForbiddenRefs = true;
return;
}
}
}
}
}
public boolean hasForbiddenRefs() {

View File

@@ -0,0 +1,24 @@
// "Replace with lambda" "false"
class DbTableBinder {
public Binder build() {
return new Bin<caret>der<DbTable>() {
public void bind(A q, DbTable dbTable) {
q.bind("name", dbTable.name);
}
};
}
}
class DbTable {
String name;
}
interface Binder <ArgType> {
void bind(A<?> sqlStatement, ArgType argType);
}
interface A<P> {
void bind(String s, String p);
}