From 0680618d017453964efafb59e88bf8fbbedd442a Mon Sep 17 00:00:00 2001 From: peter Date: Sun, 3 Feb 2013 18:24:01 +0100 Subject: [PATCH] cache variable nullability (IDEA-97762) --- .../dataFlow/ControlFlowAnalyzer.java | 2 +- .../dataFlow/DfaMemoryStateImpl.java | 2 +- .../codeInspection/dataFlow/DfaUtil.java | 35 ++++++++++++++- .../dataFlow/DfaVariableState.java | 43 ++----------------- .../dataFlow/value/DfaVariableValue.java | 27 +++++++++++- 5 files changed, 65 insertions(+), 44 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 8ebc00f44059..fb138917989a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -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()); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index e8b74efd73d0..b9c031b7be60 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -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; } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java index 065464ff47b5..b494b536b5d2 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java @@ -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 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 } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java index 02e841c89132..582acf041841 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java @@ -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(); myNotInstanceofValues = new HashSet(); - 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 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; } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java index 1c0434dd6ddc..c4294e05fdb1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java @@ -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 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; + } + }