TypeConstraint as DfaFactType

This commit is contained in:
Tagir Valeev
2017-09-15 13:33:18 +07:00
parent 021aa868ee
commit 81fe7187fe
9 changed files with 306 additions and 172 deletions
@@ -133,6 +133,48 @@ public abstract class DfaFactType<T> extends Key<T> {
return fact.toString();
}
};
/**
* This fact represents a set of possible types of this value
* {@link TypeConstraint#EMPTY} value is equivalent to absent fact (not constrained)
*/
public static final DfaFactType<TypeConstraint> TYPE_CONSTRAINT = new DfaFactType<TypeConstraint>("Type") {
@Nullable
@Override
TypeConstraint fromDfaValue(DfaValue value) {
if(value instanceof DfaTypeValue) {
TypeConstraint constraint = TypeConstraint.EMPTY.withInstanceofValue((DfaTypeValue)value);
return constraint == null || constraint.isEmpty() ? null : constraint;
}
return null;
}
@Override
boolean isSuper(@Nullable TypeConstraint superFact, @Nullable TypeConstraint subFact) {
return superFact == null || (subFact != null && superFact.isSuperStateOf(subFact));
}
@Nullable
@Override
TypeConstraint intersectFacts(@NotNull TypeConstraint left, @NotNull TypeConstraint right) {
for (DfaPsiType type : right.getInstanceofValues()) {
left = left.withInstanceofValue(type);
if (left == null) return null;
}
for (DfaPsiType type : right.getNotInstanceofValues()) {
left = left.withNotInstanceofValue(type);
if (left == null) return null;
}
return left;
}
@Nullable
@Override
TypeConstraint unionFacts(@NotNull TypeConstraint left, @NotNull TypeConstraint right) {
if(left.isSuperStateOf(right)) return left;
if(right.isSuperStateOf(left)) return right;
return null;
}
};
private DfaFactType(String name) {
super("DfaFactType: " + name);
@@ -19,7 +19,6 @@ import com.intellij.codeInspection.dataFlow.value.DfaConstValue;
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -56,13 +55,6 @@ public interface DfaMemoryState {
@Nullable
<T> T getValueFact(@NotNull DfaFactType<T> factType, @NotNull DfaValue value);
/**
* @param value to determine its type
* @return value type at this state if known (possibly erased)
*/
@Nullable
PsiType getValueType(DfaValue value);
void flushFields();
void flushVariable(DfaVariableValue variable);
@@ -1068,23 +1068,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return factType.fromDfaValue(value);
}
@Nullable
@Override
public PsiType getValueType(DfaValue value) {
if (value instanceof DfaTypeValue) {
return ((DfaTypeValue)value).getDfaType().getPsiType();
}
if (value instanceof DfaVariableValue) {
DfaVariableState state = getVariableState((DfaVariableValue)value);
Set<DfaPsiType> values = state.getInstanceofValues();
if (!values.isEmpty()) {
return values.iterator().next().getPsiType();
}
return ((DfaVariableValue)value).getVariableType();
}
return null;
}
@NotNull
private DfaValue resolveVariableValue(DfaVariableValue var) {
DfaConstValue constValue = getConstantValue(var);
@@ -20,117 +20,49 @@ import com.intellij.codeInspection.dataFlow.value.DfaPsiType;
import com.intellij.codeInspection.dataFlow.value.DfaTypeValue;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Objects;
class DfaVariableState {
@NotNull final Set<DfaPsiType> myInstanceofValues;
@NotNull final Set<DfaPsiType> myNotInstanceofValues;
@NotNull final DfaFactMap myFactMap;
private final int myHash;
DfaVariableState(@NotNull DfaVariableValue dfaVar) {
this(Collections.emptySet(), Collections.emptySet(), dfaVar.getInherentFacts());
this(dfaVar.getInherentFacts());
}
public boolean isSuperStateOf(DfaVariableState that) {
if(!that.myNotInstanceofValues.containsAll(myNotInstanceofValues)) return false;
if(!that.myInstanceofValues.containsAll(myInstanceofValues)) return false;
return myFactMap.isSuperStateOf(that.myFactMap);
}
DfaVariableState(@NotNull Set<DfaPsiType> instanceofValues,
@NotNull Set<DfaPsiType> notInstanceofValues,
@NotNull DfaFactMap factMap) {
myInstanceofValues = instanceofValues;
myNotInstanceofValues = notInstanceofValues;
DfaVariableState(@NotNull DfaFactMap factMap) {
myFactMap = factMap;
myHash = Objects.hash(myInstanceofValues, myNotInstanceofValues, myFactMap);
}
private boolean checkInstanceofValue(@NotNull DfaPsiType dfaType) {
if (myInstanceofValues.contains(dfaType)) return true;
for (DfaPsiType dfaTypeValue : myNotInstanceofValues) {
if (dfaTypeValue.isAssignableFrom(dfaType)) return false;
}
for (DfaPsiType dfaTypeValue : myInstanceofValues) {
if (!dfaType.isConvertibleFrom(dfaTypeValue)) return false;
}
return true;
myHash = myFactMap.hashCode();
}
@Nullable
DfaVariableState withInstanceofValue(@NotNull DfaTypeValue dfaType) {
if (dfaType.getDfaType().getPsiType() instanceof PsiPrimitiveType) return this;
if (checkInstanceofValue(dfaType.getDfaType())) {
DfaVariableState result = dfaType.isNullable() ? withFact(DfaFactType.CAN_BE_NULL, true) : this;
List<DfaPsiType> moreGeneric = ContainerUtil.newArrayList();
for (DfaPsiType alreadyInstanceof : myInstanceofValues) {
if (dfaType.getDfaType().isAssignableFrom(alreadyInstanceof)) {
return result;
}
if (alreadyInstanceof.isAssignableFrom(dfaType.getDfaType())) {
moreGeneric.add(alreadyInstanceof);
}
}
HashSet<DfaPsiType> newInstanceof = ContainerUtil.newHashSet(myInstanceofValues);
newInstanceof.removeAll(moreGeneric);
newInstanceof.add(dfaType.getDfaType());
result = createCopy(newInstanceof, myNotInstanceofValues, result.myFactMap);
return result;
}
return null;
TypeConstraint typeConstraint = getTypeConstraint();
TypeConstraint newTypeConstraint = typeConstraint.withInstanceofValue(dfaType);
if (newTypeConstraint == null) return null;
DfaVariableState result = dfaType.isNullable() ? withFact(DfaFactType.CAN_BE_NULL, true) : this;
return result.withFact(DfaFactType.TYPE_CONSTRAINT, newTypeConstraint);
}
@Nullable
DfaVariableState withNotInstanceofValue(@NotNull DfaTypeValue dfaType) {
if (myNotInstanceofValues.contains(dfaType.getDfaType())) return this;
for (DfaPsiType dfaTypeValue : myInstanceofValues) {
if (dfaType.getDfaType().isAssignableFrom(dfaTypeValue)) return null;
}
List<DfaPsiType> moreSpecific = ContainerUtil.newArrayList();
for (DfaPsiType alreadyNotInstanceof : myNotInstanceofValues) {
if (alreadyNotInstanceof.isAssignableFrom(dfaType.getDfaType())) {
return this;
}
if (dfaType.getDfaType().isAssignableFrom(alreadyNotInstanceof)) {
moreSpecific.add(alreadyNotInstanceof);
}
}
HashSet<DfaPsiType> newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues);
newNotInstanceof.removeAll(moreSpecific);
newNotInstanceof.add(dfaType.getDfaType());
return createCopy(myInstanceofValues, newNotInstanceof, myFactMap);
TypeConstraint typeConstraint = getTypeConstraint();
TypeConstraint newTypeConstraint = typeConstraint.withNotInstanceofValue(dfaType);
return newTypeConstraint == null ? null : withFact(DfaFactType.TYPE_CONSTRAINT, newTypeConstraint);
}
@NotNull
DfaVariableState withoutType(@NotNull DfaPsiType type) {
if (myInstanceofValues.contains(type)) {
HashSet<DfaPsiType> newInstanceof = ContainerUtil.newHashSet(myInstanceofValues);
newInstanceof.remove(type);
return createCopy(newInstanceof, myNotInstanceofValues, myFactMap);
}
if (myNotInstanceofValues.contains(type)) {
HashSet<DfaPsiType> newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues);
newNotInstanceof.remove(type);
return createCopy(myInstanceofValues, newNotInstanceof, myFactMap);
}
return this;
return withFact(DfaFactType.TYPE_CONSTRAINT, getTypeConstraint().withoutType(type));
}
public int hashCode() {
@@ -141,35 +73,16 @@ class DfaVariableState {
if (obj == this) return true;
if (!(obj instanceof DfaVariableState)) return false;
DfaVariableState aState = (DfaVariableState) obj;
return myHash == aState.myHash &&
myInstanceofValues.equals(aState.myInstanceofValues) &&
myNotInstanceofValues.equals(aState.myNotInstanceofValues) &&
Objects.equals(myFactMap, aState.myFactMap);
return myHash == aState.myHash && Objects.equals(myFactMap, aState.myFactMap);
}
@NotNull
protected DfaVariableState createCopy(@NotNull Set<DfaPsiType> instanceofValues,
@NotNull Set<DfaPsiType> notInstanceofValues,
@NotNull DfaFactMap factMap) {
return new DfaVariableState(instanceofValues, notInstanceofValues, factMap);
protected DfaVariableState createCopy(@NotNull DfaFactMap factMap) {
return new DfaVariableState(factMap);
}
public String toString() {
@NonNls StringBuilder buf = new StringBuilder("State:");
if (!myInstanceofValues.isEmpty()) {
buf.append(" instanceof ").append(StringUtil.join(myInstanceofValues, ","));
}
if (!myNotInstanceofValues.isEmpty()) {
buf.append(" not instanceof ").append(StringUtil.join(myNotInstanceofValues, ","));
}
String factString = myFactMap.toString();
if(!factString.isEmpty()) {
buf.append(" ").append(factString);
}
return buf.toString();
return "State: " + myFactMap;
}
@NotNull
@@ -189,7 +102,7 @@ class DfaVariableState {
@NotNull
<T> DfaVariableState withFact(DfaFactType<T> type, T value) {
DfaFactMap factMap = myFactMap.with(type, value);
return myFactMap.equals(factMap) ? this : createCopy(myInstanceofValues, myNotInstanceofValues, factMap);
return myFactMap.equals(factMap) ? this : createCopy(factMap);
}
<T> DfaVariableState withoutFact(DfaFactType<T> type) {
@@ -199,9 +112,7 @@ class DfaVariableState {
@Nullable
<T> DfaVariableState intersectFact(DfaFactType<T> type, T value) {
DfaFactMap factMap = myFactMap.intersect(type, value);
return factMap == null
? null
: myFactMap.equals(factMap) ? this : createCopy(myInstanceofValues, myNotInstanceofValues, factMap);
return factMap == null ? null : myFactMap.equals(factMap) ? this : createCopy(factMap);
}
@NotNull
@@ -215,13 +126,9 @@ class DfaVariableState {
}
@NotNull
public Set<DfaPsiType> getInstanceofValues() {
return myInstanceofValues;
}
@NotNull
public Set<DfaPsiType> getNotInstanceofValues() {
return myNotInstanceofValues;
public TypeConstraint getTypeConstraint() {
TypeConstraint fact = getFact(DfaFactType.TYPE_CONSTRAINT);
return fact == null ? TypeConstraint.EMPTY : fact;
}
@Nullable
@@ -33,7 +33,6 @@ import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
/**
@@ -138,8 +137,7 @@ class NullParameterConstraintChecker extends DataFlowRunner {
super(factory);
for (PsiParameter parameter : myPossiblyViolatedParameters) {
setVariableState(getFactory().getVarFactory().createVariableValue(parameter, false),
new DfaVariableState(Collections.emptySet(), Collections.emptySet(),
DfaFactMap.EMPTY.with(DfaFactType.CAN_BE_NULL, true)));
new DfaVariableState(DfaFactMap.EMPTY.with(DfaFactType.CAN_BE_NULL, true)));
}
}
@@ -20,6 +20,7 @@ import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet;
import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType;
import com.intellij.lang.jvm.JvmModifier;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
@@ -477,6 +478,28 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
}
@NotNull
private static PsiMethod findSpecificMethod(@NotNull PsiMethod method, @NotNull DfaMemoryState state, @Nullable DfaValue qualifier) {
if (qualifier == null ||
method.hasModifier(JvmModifier.STATIC) ||
method.hasModifier(JvmModifier.FINAL) ||
method.hasModifier(JvmModifier.PRIVATE)) {
return method;
}
TypeConstraint constraint = state.getValueFact(DfaFactType.TYPE_CONSTRAINT, qualifier);
PsiClass specificQualifierClass = PsiUtil.resolveClassInClassTypeOnly(constraint == null ? null : constraint.getPsiType());
PsiClass qualifierClass = method.getContainingClass();
if (specificQualifierClass != null && qualifierClass != null &&
!specificQualifierClass.equals(qualifierClass) &&
InheritanceUtil.isInheritorOrSelf(specificQualifierClass, qualifierClass, true)) {
PsiMethod realMethod = specificQualifierClass.findMethodBySignature(method, true);
if (realMethod != null) {
return realMethod;
}
}
return method;
}
@NotNull
private static DfaValue getMethodResultValue(MethodCallInstruction instruction,
@Nullable DfaValue qualifierValue,
@@ -520,19 +543,13 @@ public class StandardInstructionVisitor extends InstructionVisitor {
Nullness nullability = instruction.getReturnNullability();
PsiMethod targetMethod = instruction.getTargetMethod();
if (targetMethod != null) {
PsiClass specificQualifierClass = PsiUtil.resolveClassInClassTypeOnly(state.getValueType(qualifierValue));
PsiClass qualifierClass = targetMethod.getContainingClass();
if (specificQualifierClass != null && qualifierClass != null &&
!specificQualifierClass.equals(qualifierClass) &&
InheritanceUtil.isInheritorOrSelf(specificQualifierClass, qualifierClass, true)) {
PsiMethod realMethod = specificQualifierClass.findMethodBySignature(targetMethod, true);
if (realMethod != null && realMethod != targetMethod) {
nullability = DfaPsiUtil.getElementNullability(type, realMethod);
PsiType returnType = realMethod.getReturnType();
if(returnType != null && TypeConversionUtil.erasure(type).isAssignableFrom(returnType)) {
// possibly covariant return type
type = returnType;
}
PsiMethod realMethod = findSpecificMethod(targetMethod, state, qualifierValue);
if (realMethod != targetMethod) {
nullability = DfaPsiUtil.getElementNullability(type, realMethod);
PsiType returnType = realMethod.getReturnType();
if (returnType != null && TypeConversionUtil.erasure(type).isAssignableFrom(returnType)) {
// possibly covariant return type
type = returnType;
}
}
if (nullability == Nullness.UNKNOWN) {
@@ -700,7 +717,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
return checkComparisonWithKnownValue(instruction, runner, memState, relationType, leftValue, rightValue);
}
}
if (dfaRight instanceof DfaConstValue && dfaLeft instanceof DfaVariableValue) {
Object value = ((DfaConstValue)dfaRight).getValue();
if (value instanceof Number) {
@@ -430,10 +430,11 @@ class StateMerger {
for (Map.Entry<DfaVariableValue, DfaVariableState> entry : states.entrySet()) {
DfaVariableValue var = entry.getKey();
DfaVariableState variableState = entry.getValue();
for (DfaPsiType type : variableState.getInstanceofValues()) {
TypeConstraint typeConstraint = variableState.getTypeConstraint();
for (DfaPsiType type : typeConstraint.getInstanceofValues()) {
result.add(new InstanceofFact(var, true, type));
}
for (DfaPsiType type : variableState.getNotInstanceofValues()) {
for (DfaPsiType type : typeConstraint.getNotInstanceofValues()) {
result.add(new InstanceofFact(var, false, type));
}
}
@@ -0,0 +1,201 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInspection.dataFlow.value.DfaPsiType;
import com.intellij.codeInspection.dataFlow.value.DfaTypeValue;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.psi.PsiType;
import com.intellij.util.containers.ContainerUtil;
import one.util.streamex.EntryStream;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* Immutable class representing a number of non-primitive type constraints applied to some value.
* There are two types of constrains: value is instance of some type and value is not an instance of some type.
*/
public final class TypeConstraint {
/**
* An instance representing no constraints
*/
public static final TypeConstraint EMPTY = new TypeConstraint(Collections.emptySet(), Collections.emptySet());
@NotNull private final Set<DfaPsiType> myInstanceofValues;
@NotNull private final Set<DfaPsiType> myNotInstanceofValues;
private TypeConstraint(@NotNull Set<DfaPsiType> instanceofValues, @NotNull Set<DfaPsiType> notInstanceofValues) {
myInstanceofValues = instanceofValues;
myNotInstanceofValues = notInstanceofValues;
}
private static TypeConstraint create(@NotNull Set<DfaPsiType> instanceofValues, @NotNull Set<DfaPsiType> notInstanceofValues) {
if (instanceofValues.isEmpty() && notInstanceofValues.isEmpty()) {
return EMPTY;
}
if (instanceofValues.isEmpty()) {
instanceofValues = Collections.emptySet();
}
else if (instanceofValues.size() == 1) {
instanceofValues = Collections.singleton(instanceofValues.iterator().next());
}
if (notInstanceofValues.isEmpty()) {
notInstanceofValues = Collections.emptySet();
}
else if (notInstanceofValues.size() == 1) {
notInstanceofValues = Collections.singleton(notInstanceofValues.iterator().next());
}
return new TypeConstraint(instanceofValues, notInstanceofValues);
}
boolean checkInstanceofValue(@NotNull DfaPsiType dfaType) {
if (myInstanceofValues.contains(dfaType)) return true;
for (DfaPsiType dfaTypeValue : myNotInstanceofValues) {
if (dfaTypeValue.isAssignableFrom(dfaType)) return false;
}
for (DfaPsiType dfaTypeValue : myInstanceofValues) {
if (!dfaType.isConvertibleFrom(dfaTypeValue)) return false;
}
return true;
}
@Nullable
TypeConstraint withInstanceofValue(@NotNull DfaTypeValue dfaType) {
return withInstanceofValue(dfaType.getDfaType());
}
@Nullable
TypeConstraint withInstanceofValue(@NotNull DfaPsiType type) {
if (type.getPsiType() instanceof PsiPrimitiveType) return this;
if (!checkInstanceofValue(type)) {
return null;
}
List<DfaPsiType> moreGeneric = new ArrayList<>();
for (DfaPsiType alreadyInstanceof : myInstanceofValues) {
if (type.isAssignableFrom(alreadyInstanceof)) {
return this;
}
if (alreadyInstanceof.isAssignableFrom(type)) {
moreGeneric.add(alreadyInstanceof);
}
}
Set<DfaPsiType> newInstanceof = ContainerUtil.newHashSet(myInstanceofValues);
newInstanceof.removeAll(moreGeneric);
newInstanceof.add(type);
return create(newInstanceof, myNotInstanceofValues);
}
@Nullable
TypeConstraint withNotInstanceofValue(@NotNull DfaTypeValue dfaType) {
return withNotInstanceofValue(dfaType.getDfaType());
}
@Nullable
TypeConstraint withNotInstanceofValue(DfaPsiType type) {
if (myNotInstanceofValues.contains(type)) return this;
for (DfaPsiType dfaTypeValue : myInstanceofValues) {
if (type.isAssignableFrom(dfaTypeValue)) return null;
}
List<DfaPsiType> moreSpecific = new ArrayList<>();
for (DfaPsiType alreadyNotInstanceof : myNotInstanceofValues) {
if (alreadyNotInstanceof.isAssignableFrom(type)) {
return this;
}
if (type.isAssignableFrom(alreadyNotInstanceof)) {
moreSpecific.add(alreadyNotInstanceof);
}
}
Set<DfaPsiType> newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues);
newNotInstanceof.removeAll(moreSpecific);
newNotInstanceof.add(type);
return create(myInstanceofValues, newNotInstanceof);
}
@NotNull
TypeConstraint withoutType(@NotNull DfaPsiType type) {
if (myInstanceofValues.contains(type)) {
HashSet<DfaPsiType> newInstanceof = ContainerUtil.newHashSet(myInstanceofValues);
newInstanceof.remove(type);
return create(newInstanceof, myNotInstanceofValues);
}
if (myNotInstanceofValues.contains(type)) {
HashSet<DfaPsiType> newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues);
newNotInstanceof.remove(type);
return create(myInstanceofValues, newNotInstanceof);
}
return this;
}
@Nullable
public PsiType getPsiType() {
if (myInstanceofValues.isEmpty()) {
return null;
}
return myInstanceofValues.iterator().next().getPsiType();
}
boolean isSuperStateOf(@NotNull TypeConstraint that) {
return that.myNotInstanceofValues.containsAll(myNotInstanceofValues) && that.myInstanceofValues.containsAll(myInstanceofValues);
}
@NotNull
public Set<DfaPsiType> getInstanceofValues() {
return Collections.unmodifiableSet(myInstanceofValues);
}
@NotNull
public Set<DfaPsiType> getNotInstanceofValues() {
return Collections.unmodifiableSet(myNotInstanceofValues);
}
public boolean isEmpty() {
return myInstanceofValues.isEmpty() && myNotInstanceofValues.isEmpty();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TypeConstraint that = (TypeConstraint)o;
return Objects.equals(myInstanceofValues, that.myInstanceofValues) &&
Objects.equals(myNotInstanceofValues, that.myNotInstanceofValues);
}
@Override
public int hashCode() {
return Objects.hash(myInstanceofValues, myNotInstanceofValues);
}
@Override
public String toString() {
return EntryStream.of("instanceof ", myInstanceofValues,
"not instanceof ", myNotInstanceofValues)
.removeValues(Set::isEmpty)
.mapKeyValue((prefix, set) -> StreamEx.of(set).joining(",", prefix, ""))
.joining(" ");
}
}
@@ -16,7 +16,6 @@
package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInspection.dataFlow.value.DfaPsiType;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
@@ -25,8 +24,6 @@ import com.intellij.util.containers.FList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* @author Gregory.Shrago
*/
@@ -74,34 +71,30 @@ class ValuableDataFlowRunner extends DataFlowRunner {
myConcatenation = FList.emptyList();
}
private ValuableDfaVariableState(Set<DfaPsiType> instanceofValues,
Set<DfaPsiType> notInstanceofValues,
DfaValue value,
private ValuableDfaVariableState(DfaValue value,
@NotNull FList<PsiExpression> concatenation,
@NotNull DfaFactMap factMap) {
super(instanceofValues, notInstanceofValues, factMap);
super(factMap);
myValue = value;
myConcatenation = concatenation;
}
@NotNull
@Override
protected DfaVariableState createCopy(@NotNull Set<DfaPsiType> instanceofValues,
@NotNull Set<DfaPsiType> notInstanceofValues,
@NotNull DfaFactMap factMap) {
return new ValuableDfaVariableState(instanceofValues, notInstanceofValues, myValue, myConcatenation, factMap);
protected DfaVariableState createCopy(@NotNull DfaFactMap factMap) {
return new ValuableDfaVariableState(myValue, myConcatenation, factMap);
}
@NotNull
@Override
public DfaVariableState withValue(@Nullable final DfaValue value) {
if (value == myValue) return this;
return new ValuableDfaVariableState(myInstanceofValues, myNotInstanceofValues, value, myConcatenation, myFactMap);
return new ValuableDfaVariableState(value, myConcatenation, myFactMap);
}
ValuableDfaVariableState withExpression(@NotNull final FList<PsiExpression> concatenation) {
if (concatenation == myConcatenation) return this;
return new ValuableDfaVariableState(myInstanceofValues, myNotInstanceofValues, myValue, concatenation, myFactMap);
return new ValuableDfaVariableState(myValue, concatenation, myFactMap);
}
@Override