cache variable nullability (IDEA-97762)

This commit is contained in:
peter
2013-02-03 22:42:55 +01:00
parent 1fccc8e000
commit 0680618d01
5 changed files with 65 additions and 44 deletions
@@ -1592,7 +1592,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
return myFactory.getVarFactory().createVariableValue(var, refExpr.getType(), false, null, isCall);
}
if (DfaVariableState.isFinalField(var)) {
if (DfaUtil.isFinalField(var)) {
DfaVariableValue qualifierValue = createChainedVariableValue(qualifier);
if (qualifierValue != null) {
return myFactory.getVarFactory().createVariableValue(var, refExpr.getType(), false, qualifierValue, isCall || qualifierValue.isViaMethods());
@@ -790,7 +790,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
public void flushVariable(@NotNull DfaVariableValue variable) {
PsiVariable psiVariable = variable.getPsiVariable();
if (DfaVariableState.isFinalField(psiVariable)) {
if (DfaUtil.isFinalField(psiVariable)) {
return;
}
@@ -21,6 +21,7 @@ import com.intellij.codeInspection.dataFlow.instructions.Instruction;
import com.intellij.codeInspection.dataFlow.instructions.PushInstruction;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.nullable.NullableStuffInspection;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.MultiValuesMap;
import com.intellij.openapi.util.Ref;
@@ -86,7 +87,7 @@ public class DfaUtil {
}
@Nullable
static Boolean getElementNullability(@Nullable PsiType resultType, @Nullable PsiModifierListOwner owner) {
public static Boolean getElementNullability(@Nullable PsiType resultType, @Nullable PsiModifierListOwner owner) {
if (owner == null) {
return null;
}
@@ -114,6 +115,38 @@ public class DfaUtil {
return null;
}
public static boolean isNullableInitialized(PsiVariable var, boolean nullable) {
if (!isFinalField(var)) {
return false;
}
List<PsiExpression> initializers = NullableStuffInspection.findAllConstructorInitializers((PsiField)var);
if (initializers.isEmpty()) {
return false;
}
for (PsiExpression expression : initializers) {
if (!(expression instanceof PsiReferenceExpression)) {
return false;
}
PsiElement target = ((PsiReferenceExpression)expression).resolve();
if (!(target instanceof PsiParameter)) {
return false;
}
if (nullable && NullableNotNullManager.isNullable((PsiParameter)target)) {
return true;
}
if (!nullable && !NullableNotNullManager.isNotNull((PsiParameter)target)) {
return false;
}
}
return !nullable;
}
public static boolean isFinalField(PsiVariable var) {
return var.hasModifierProperty(PsiModifier.FINAL) && !var.hasModifierProperty(PsiModifier.TRANSIENT) && var instanceof PsiField;
}
public static enum Nullness {
NOT_NULL,NULL,UNKNOWN
}
@@ -24,11 +24,9 @@
*/
package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInspection.dataFlow.value.DfaTypeValue;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.nullable.NullableStuffInspection;
import com.intellij.psi.*;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
@@ -37,7 +35,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class DfaVariableState implements Cloneable {
@@ -49,10 +46,10 @@ public class DfaVariableState implements Cloneable {
public DfaVariableState(@NotNull DfaVariableValue dfaVar) {
myInstanceofValues = new HashSet<DfaTypeValue>();
myNotInstanceofValues = new HashSet<DfaTypeValue>();
PsiVariable var = dfaVar.getPsiVariable();
Boolean nullability = DfaUtil.getElementNullability(dfaVar.getVariableType(), var);
myNullable = nullability == Boolean.TRUE || var != null && isNullableInitialized(var, true);
myVariableIsDeclaredNotNull = nullability == Boolean.FALSE || var != null && isNullableInitialized(var, false);
Boolean nullability = dfaVar.getInherentNullability();
myNullable = nullability == Boolean.TRUE;
myVariableIsDeclaredNotNull = nullability == Boolean.FALSE;
}
protected DfaVariableState(final DfaVariableState toClone) {
@@ -62,38 +59,6 @@ public class DfaVariableState implements Cloneable {
myVariableIsDeclaredNotNull = toClone.myVariableIsDeclaredNotNull;
}
private static boolean isNullableInitialized(PsiVariable var, boolean nullable) {
if (!isFinalField(var)) {
return false;
}
List<PsiExpression> initializers = NullableStuffInspection.findAllConstructorInitializers((PsiField)var);
if (initializers.isEmpty()) {
return false;
}
for (PsiExpression expression : initializers) {
if (!(expression instanceof PsiReferenceExpression)) {
return false;
}
PsiElement target = ((PsiReferenceExpression)expression).resolve();
if (!(target instanceof PsiParameter)) {
return false;
}
if (nullable && NullableNotNullManager.isNullable((PsiParameter)target)) {
return true;
}
if (!nullable && !NullableNotNullManager.isNotNull((PsiParameter)target)) {
return false;
}
}
return !nullable;
}
public static boolean isFinalField(PsiVariable var) {
return var.hasModifierProperty(PsiModifier.FINAL) && !var.hasModifierProperty(PsiModifier.TRANSIENT) && var instanceof PsiField;
}
public boolean isNullable() {
return myNullable;
}
@@ -24,8 +24,9 @@
*/
package com.intellij.codeInspection.dataFlow.value;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiVariable;
import com.intellij.codeInspection.dataFlow.DfaUtil;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.Nullable;
@@ -92,6 +93,7 @@ public class DfaVariableValue extends DfaValue {
@Nullable private DfaVariableValue myQualifier;
private boolean myIsNegated;
private boolean myViaMethods;
private Ref<Boolean> myInherentNullability;
private DfaVariableValue(PsiVariable variable, PsiType varType, boolean isNegated, DfaValueFactory factory, @Nullable DfaVariableValue qualifier, boolean viaMethods) {
super(factory);
@@ -147,4 +149,25 @@ public class DfaVariableValue extends DfaValue {
public boolean isViaMethods() {
return myViaMethods;
}
public Boolean getInherentNullability() {
if (myInherentNullability != null) {
return myInherentNullability.get();
}
PsiVariable var = getPsiVariable();
Boolean nullability = DfaUtil.getElementNullability(getVariableType(), var);
if (nullability == null && var != null) {
if (DfaUtil.isNullableInitialized(var, true)) {
nullability = true;
} else if (DfaUtil.isNullableInitialized(var, false)) {
nullability = false;
}
}
myInherentNullability = Ref.create(nullability);
return nullability;
}
}