mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
cache variable nullability (IDEA-97762)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
+25
-2
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user