diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java b/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java
index 82d75edcde45..a002e50bdb3f 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
import com.intellij.codeInspection.reference.*;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.*;
+import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -99,17 +100,22 @@ class CanBeFinalAnnotator extends RefGraphAnnotatorEx {
RefElement refFrom,
boolean referencedFromClassInitializer,
boolean forReading,
- boolean forWriting) {
+ boolean forWriting,
+ PsiElement referenceElement) {
if (!(refWhat instanceof RefField)) return;
if (!(refFrom instanceof RefMethod) ||
!((RefMethod)refFrom).isConstructor() ||
((PsiField)refWhat.getElement()).hasInitializer() ||
((RefMethod)refFrom).getOwnerClass() != ((RefField)refWhat).getOwnerClass() ||
((RefField)refWhat).isStatic()) {
- if (!referencedFromClassInitializer && forWriting) {
+ if (forWriting &&
+ !(referencedFromClassInitializer && PsiTreeUtil.getParentOfType(referenceElement, PsiLambdaExpression.class, true) == null)) {
((RefFieldImpl)refWhat).setFlag(false, CAN_BE_FINAL_MASK);
}
}
+ else if (forWriting && PsiTreeUtil.getParentOfType(referenceElement, PsiLambdaExpression.class, true) != null) {
+ ((RefFieldImpl)refWhat).setFlag(false, CAN_BE_FINAL_MASK);
+ }
}
@Override
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java
index efab8d209ff6..2116b4e7b51b 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java
@@ -76,7 +76,7 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField {
}
setUsedQualifiedOutsidePackageFlag(refFrom, expressionFrom);
- getRefManager().fireNodeMarkedReferenced(this, refFrom, referencedFromClassInitializer, forReading, forWriting);
+ getRefManager().fireNodeMarkedReferenced(this, refFrom, referencedFromClassInitializer, forReading, forWriting, expressionFrom);
}
@Override
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java
index 28208062735a..9d543e39c613 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java
@@ -260,7 +260,7 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa
protected void markReferenced(final RefElementImpl refFrom, PsiElement psiFrom, PsiElement psiWhat, final boolean forWriting, boolean forReading, PsiReferenceExpression expressionFrom) {
addInReference(refFrom);
setUsedQualifiedOutsidePackageFlag(refFrom, expressionFrom);
- getRefManager().fireNodeMarkedReferenced(this, refFrom, false, forReading, forWriting);
+ getRefManager().fireNodeMarkedReferenced(this, refFrom, false, forReading, forWriting, expressionFrom);
}
void setUsedQualifiedOutsidePackageFlag(RefElementImpl refFrom, PsiReferenceExpression expressionFrom) {
diff --git a/java/java-tests/testData/inspection/canBeFinal/assignedFromLambda/expected.xml b/java/java-tests/testData/inspection/canBeFinal/assignedFromLambda/expected.xml
new file mode 100644
index 000000000000..9ac879d78616
--- /dev/null
+++ b/java/java-tests/testData/inspection/canBeFinal/assignedFromLambda/expected.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/java/java-tests/testData/inspection/canBeFinal/assignedFromLambda/src/Foo.java b/java/java-tests/testData/inspection/canBeFinal/assignedFromLambda/src/Foo.java
new file mode 100644
index 000000000000..0617acd68c1b
--- /dev/null
+++ b/java/java-tests/testData/inspection/canBeFinal/assignedFromLambda/src/Foo.java
@@ -0,0 +1,8 @@
+abstract class Foo {
+ private String foo;
+
+ public A(String foo) {
+ this.foo = foo;
+ Runnable r = () -> {this.foo = "";};
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/canBeFinal/assignedFromLambdaInClassInitializer/expected.xml b/java/java-tests/testData/inspection/canBeFinal/assignedFromLambdaInClassInitializer/expected.xml
new file mode 100644
index 000000000000..9ac879d78616
--- /dev/null
+++ b/java/java-tests/testData/inspection/canBeFinal/assignedFromLambdaInClassInitializer/expected.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/java/java-tests/testData/inspection/canBeFinal/assignedFromLambdaInClassInitializer/src/Foo.java b/java/java-tests/testData/inspection/canBeFinal/assignedFromLambdaInClassInitializer/src/Foo.java
new file mode 100644
index 000000000000..c970101d56a9
--- /dev/null
+++ b/java/java-tests/testData/inspection/canBeFinal/assignedFromLambdaInClassInitializer/src/Foo.java
@@ -0,0 +1,6 @@
+abstract class Foo {
+ private String foo = "1";
+ {
+ Runnable r = () -> {this.foo = "";};
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/CanBeFinalTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/CanBeFinalTest.java
index 043c9a655c91..602166aa1aea 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInspection/CanBeFinalTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/CanBeFinalTest.java
@@ -47,6 +47,14 @@ public class CanBeFinalTest extends InspectionTestCase {
doTest();
}
+ public void testassignedFromLambda() {
+ doTest();
+ }
+
+ public void testassignedFromLambdaInClassInitializer() {
+ doTest();
+ }
+
public void testsimpleClassInheritance() {
doTest();
}
diff --git a/platform/analysis-api/src/com/intellij/codeInspection/reference/RefGraphAnnotator.java b/platform/analysis-api/src/com/intellij/codeInspection/reference/RefGraphAnnotator.java
index ebae56ed25d0..752dff46259c 100644
--- a/platform/analysis-api/src/com/intellij/codeInspection/reference/RefGraphAnnotator.java
+++ b/platform/analysis-api/src/com/intellij/codeInspection/reference/RefGraphAnnotator.java
@@ -55,6 +55,26 @@ public abstract class RefGraphAnnotator {
boolean referencedFromClassInitializer) {
}
+ /**
+ * Called when a reference to the specified element has been found.
+ *
+ * @param refWhat the referenced element.
+ * @param refFrom the referencing element.
+ * @param referencedFromClassInitializer if true, {@code refFrom} is a class and the reference
+ * has been found in its initializer block.
+ * @param forReading used for reading
+ * @param forWriting used for writing
+ * @param referenceElement reference element in refFrom
+ */
+ public void onMarkReferenced(RefElement refWhat,
+ RefElement refFrom,
+ boolean referencedFromClassInitializer,
+ boolean forReading,
+ boolean forWriting,
+ PsiElement referenceElement) {
+ onMarkReferenced(refWhat, refFrom, referencedFromClassInitializer, forReading, forWriting);
+ }
+
/**
* Called when a reference to the specified element has been found.
*
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java
index ffd9b1706008..cac652b97a97 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java
@@ -169,6 +169,17 @@ public class RefManagerImpl extends RefManager {
annotator.onMarkReferenced(refWhat, refFrom, referencedFromClassInitializer, forReading, forWriting);
}
}
+
+ void fireNodeMarkedReferenced(RefElement refWhat,
+ RefElement refFrom,
+ boolean referencedFromClassInitializer,
+ final boolean forReading,
+ final boolean forWriting,
+ PsiElement element) {
+ for (RefGraphAnnotator annotator : myGraphAnnotators) {
+ annotator.onMarkReferenced(refWhat, refFrom, referencedFromClassInitializer, forReading, forWriting, element);
+ }
+ }
public void fireNodeMarkedReferenced(PsiElement what, PsiElement from) {
for (RefGraphAnnotator annotator : myGraphAnnotators) {