field can be final: assigned from lambda in constructor (IDEA-170073)

This commit is contained in:
Anna Kozlova
2018-01-03 21:10:47 +01:00
parent b72aae1b8a
commit 7cbfe6c753
10 changed files with 69 additions and 4 deletions
@@ -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
@@ -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
@@ -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) {
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems />
@@ -0,0 +1,8 @@
abstract class Foo {
private String foo;
public A(String foo) {
this.foo = foo;
Runnable r = () -> {this.foo = "";};
}
}
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems />
@@ -0,0 +1,6 @@
abstract class Foo {
private String foo = "1";
{
Runnable r = () -> {this.foo = "";};
}
}
@@ -47,6 +47,14 @@ public class CanBeFinalTest extends InspectionTestCase {
doTest();
}
public void testassignedFromLambda() {
doTest();
}
public void testassignedFromLambdaInClassInitializer() {
doTest();
}
public void testsimpleClassInheritance() {
doTest();
}
@@ -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.
*
@@ -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) {