lambda: do not suggest to replace with lambda when refs to final fields exist in body (IDEA-111026); final initializer

This commit is contained in:
anna
2013-10-24 12:16:19 +02:00
parent 0b790578ad
commit a7316ca594
5 changed files with 58 additions and 3 deletions

View File

@@ -1723,7 +1723,7 @@ public class HighlightUtil extends HighlightUtilBase {
if (expression.getTextRange().getStartOffset() >= referencedField.getTextRange().getEndOffset()) return null;
// only simple reference can be illegal
if (expression.getQualifierExpression() != null) return null;
PsiField initField = findEnclosingFieldInitializer(expression);
PsiField initField = findEnclosingFieldInitializer(expression, true);
PsiClassInitializer classInitializer = findParentClassInitializer(expression);
if (initField == null && classInitializer == null) return null;
// instance initializers may access static fields
@@ -1743,7 +1743,12 @@ public class HighlightUtil extends HighlightUtilBase {
* @return field that has initializer with this element as subexpression or null if not found
*/
@Nullable
static PsiField findEnclosingFieldInitializer(@Nullable PsiElement element) {
public static PsiField findEnclosingFieldInitializer(@Nullable PsiElement element) {
return findEnclosingFieldInitializer(element, false);
}
@Nullable
public static PsiField findEnclosingFieldInitializer(@Nullable PsiElement element, boolean stopAtLambda) {
while (element != null) {
PsiElement parent = element.getParent();
if (parent instanceof PsiField) {
@@ -1751,7 +1756,7 @@ public class HighlightUtil extends HighlightUtilBase {
if (element == field.getInitializer()) return field;
if (field instanceof PsiEnumConstant && element == ((PsiEnumConstant)field).getArgumentList()) return field;
}
if (element instanceof PsiClass || element instanceof PsiMethod || parent instanceof PsiLambdaExpression) return null;
if (element instanceof PsiClass || element instanceof PsiMethod || (stopAtLambda && parent instanceof PsiLambdaExpression)) return null;
element = parent;
}
return null;

View File

@@ -17,6 +17,7 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.ChangeContextUtil;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
@@ -84,6 +85,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
body.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitMethodCallExpression(PsiMethodCallExpression methodCallExpression) {
if (bodyContainsForbiddenRefs[0]) return;
super.visitMethodCallExpression(methodCallExpression);
final PsiMethod psiMethod = methodCallExpression.resolveMethod();
if (psiMethod == methods[0] ||
@@ -97,6 +99,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
@Override
public void visitThisExpression(PsiThisExpression expression) {
if (bodyContainsForbiddenRefs[0]) return;
if (expression.getQualifier() == null) {
bodyContainsForbiddenRefs[0] = true;
}
@@ -104,6 +107,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
@Override
public void visitSuperExpression(PsiSuperExpression expression) {
if (bodyContainsForbiddenRefs[0]) return;
if (expression.getQualifier() == null) {
bodyContainsForbiddenRefs[0] = true;
}
@@ -111,9 +115,28 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
@Override
public void visitLocalVariable(PsiLocalVariable variable) {
if (bodyContainsForbiddenRefs[0]) return;
super.visitLocalVariable(variable);
locals.add(variable);
}
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
if (bodyContainsForbiddenRefs[0]) return;
super.visitReferenceExpression(expression);
if (!(expression.getParent() instanceof PsiMethodCallExpression)) {
PsiField field = HighlightUtil.findEnclosingFieldInitializer(expression);
if (field != null) {
final PsiElement resolved = expression.resolve();
if (resolved instanceof PsiField &&
((PsiField)resolved).hasModifierProperty(PsiModifier.FINAL) &&
!((PsiField)resolved).hasInitializer() &&
((PsiField)resolved).getContainingClass() == field.getContainingClass()) {
bodyContainsForbiddenRefs[0] = true;
}
}
}
}
});
if (!bodyContainsForbiddenRefs[0]) {
PsiResolveHelper helper = PsiResolveHelper.SERVICE.getInstance(body.getProject());

View File

@@ -0,0 +1,11 @@
class MyTest {
final Runnable lambdaRunnable = () -> {
System.out.println(<error descr="Variable 'o' might not have been initialized">o</error>);
};
final Object o;
MyTest(Object o) {
this.o = o;
}
}

View File

@@ -0,0 +1,15 @@
// "Replace with lambda" "false"
class MyTest {
final Runnable anonymRunnable = new Run<caret>nable() {
@Override
public void run() {
System.out.println(o);
}
};
final Object o;
MyTest(Object o) {
this.o = o;
}
}

View File

@@ -93,6 +93,7 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testUnderscores() { doTest(true);}
public void testReturnTypeAmbiguity() { doTest();}
public void testWildcardsAndFormalLambdaParams() {doTest();}
public void testFinalInitializer() {doTest();}
private void doTest() {
doTest(false);