Do not track equality on assignments like Object x = 5 (IDEA-200233)

DfaBoxedValue now reports type when possible
This commit is contained in:
Tagir Valeev
2018-10-10 13:46:10 +07:00
parent 5884c85c2c
commit b364143f5a
9 changed files with 43 additions and 12 deletions
@@ -1448,7 +1448,8 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
else if (TypeConversionUtil.isPrimitiveAndNotNull(actualType) && TypeConversionUtil.isAssignableFromPrimitiveWrapper(expectedType)) {
addConditionalRuntimeThrow();
addInstruction(new MethodCallInstruction(context, MethodType.BOXING, expectedType));
PsiType boxedType = ((PsiPrimitiveType)actualType).getBoxedType(context);
addInstruction(new MethodCallInstruction(context, MethodType.BOXING, boxedType));
}
else if (actualType != expectedType &&
TypeConversionUtil.isPrimitiveAndNotNull(actualType) &&
@@ -235,6 +235,11 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (value instanceof DfaFactMapValue) {
setVariableState(var, state.withFacts(((DfaFactMapValue)value).getFacts()));
}
else if (DfaUtil.isComparedByEquals(value.getType()) && !DfaUtil.isComparedByEquals(var.getType())) {
// Like Object x = "foo" or Object x = 5;
TypeConstraint typeConstraint = TypeConstraint.empty().withInstanceofValue(myFactory.createDfaType(value.getType()));
setVariableState(var, new DfaVariableState(getFactMap(value).with(DfaFactType.TYPE_CONSTRAINT, typeConstraint)));
}
else {
setVariableState(var, isNull(value) ? state.withFact(DfaFactType.NULLABILITY, DfaNullability.NULLABLE) : state);
DfaRelationValue dfaEqual = myFactory.getRelationFactory().createRelation(var, RelationType.EQ, value);
@@ -761,7 +766,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
DfaValue dfaTrue = myFactory.getConstFactory().getTrue();
if (dfaVar.getSource() == SpecialField.UNBOX) {
dfaVar = dfaVar.getQualifier();
dfaTrue = myFactory.getBoxedFactory().createBoxed(dfaTrue);
dfaTrue = myFactory.getBoxedFactory().createBoxed(dfaTrue, null);
}
return applyRelationCondition(myFactory.getRelationFactory().createRelation(dfaVar, RelationType.EQ, dfaTrue));
}
@@ -1162,7 +1167,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return DfaFactMap.fromDfaValue(value);
}
void setVariableState(DfaVariableValue dfaVar, DfaVariableState state) {
void setVariableState(@NotNull DfaVariableValue dfaVar, @NotNull DfaVariableState state) {
dfaVar = canonicalize(dfaVar);
if (state.equals(getDefaultState(dfaVar))) {
myVariableStates.remove(dfaVar);
@@ -1188,8 +1193,12 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (value instanceof DfaVariableValue) {
return canonicalize((DfaVariableValue)value);
}
if (value instanceof DfaBoxedValue && ((DfaBoxedValue)value).getWrappedValue() instanceof DfaVariableValue) {
return Objects.requireNonNull(myFactory.getBoxedFactory().createBoxed(canonicalize(((DfaBoxedValue)value).getWrappedValue())));
if (value instanceof DfaBoxedValue) {
DfaBoxedValue boxedValue = (DfaBoxedValue)value;
if (boxedValue.getWrappedValue() instanceof DfaVariableValue) {
DfaValue canonicalized = canonicalize(boxedValue.getWrappedValue());
return Objects.requireNonNull(myFactory.getBoxedFactory().createBoxed(canonicalized, boxedValue.getType()));
}
}
if (value instanceof DfaConstValue) {
Object constant = ((DfaConstValue)value).getValue();
@@ -347,7 +347,7 @@ public class DfaUtil {
if (TypeConversionUtil.isPrimitiveWrapper(type)) {
if (value instanceof DfaConstValue ||
(value instanceof DfaVariableValue && TypeConversionUtil.isPrimitiveAndNotNull(value.getType()))) {
DfaValue boxed = value.getFactory().getBoxedFactory().createBoxed(value);
DfaValue boxed = value.getFactory().getBoxedFactory().createBoxed(value, type);
return boxed == null ? DfaUnknownValue.getInstance() : boxed;
}
}
@@ -535,7 +535,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
if (methodType == MethodCallInstruction.MethodType.BOXING) {
DfaValue boxed = factory.getBoxedFactory().createBoxed(qualifierValue);
DfaValue boxed = factory.getBoxedFactory().createBoxed(qualifierValue, type);
return boxed == null ? factory.createTypeValue(type, Nullability.NOT_NULL) : boxed;
}
@@ -17,6 +17,7 @@ package com.intellij.codeInspection.dataFlow.value;
import com.intellij.codeInspection.dataFlow.SpecialField;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -27,10 +28,12 @@ import java.util.Map;
public class DfaBoxedValue extends DfaValue {
private final DfaValue myWrappedValue;
private final @Nullable PsiType myType;
private DfaBoxedValue(DfaValue valueToWrap, DfaValueFactory factory) {
private DfaBoxedValue(DfaValue valueToWrap, DfaValueFactory factory, @Nullable PsiType type) {
super(factory);
myWrappedValue = valueToWrap;
myType = type;
}
@NonNls
@@ -42,6 +45,12 @@ public class DfaBoxedValue extends DfaValue {
return myWrappedValue;
}
@Nullable
@Override
public PsiType getType() {
return myType;
}
public static class Factory {
private final Map<Object, DfaBoxedValue> cachedValues = new HashMap<>();
@@ -56,7 +65,7 @@ public class DfaBoxedValue extends DfaValue {
}
@Nullable
public DfaValue createBoxed(DfaValue valueToWrap) {
public DfaValue createBoxed(DfaValue valueToWrap, @Nullable PsiType type) {
if (valueToWrap instanceof DfaVariableValue && ((DfaVariableValue)valueToWrap).getSource() == SpecialField.UNBOX) {
return ((DfaVariableValue)valueToWrap).getQualifier();
}
@@ -66,7 +75,7 @@ public class DfaBoxedValue extends DfaValue {
if (o == null) return null;
DfaBoxedValue boxedValue = cachedValues.get(o);
if (boxedValue == null) {
cachedValues.put(o, boxedValue = new DfaBoxedValue(valueToWrap, myFactory));
cachedValues.put(o, boxedValue = new DfaBoxedValue(valueToWrap, myFactory, type));
}
return boxedValue;
}
@@ -71,7 +71,7 @@ public class DfaConstValue extends DfaValue {
Boolean boo = computeJavaLangBooleanFieldReference(variable);
if (boo != null) {
DfaConstValue unboxed = createFromValue(boo, PsiType.BOOLEAN);
return myFactory.getBoxedFactory().createBoxed(unboxed);
return myFactory.getBoxedFactory().createBoxed(unboxed, PsiType.BOOLEAN.getBoxedType(variable));
}
PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(variable.getInitializer());
if (initializer instanceof PsiLiteralExpression && initializer.textMatches(PsiKeyword.NULL)) {
@@ -68,7 +68,7 @@ public class aaa {
a = 4;
}
if (<warning descr="Condition 'a != null' is always 'true'">a != null</warning> && a instanceof aaa) {
if (<warning descr="Condition 'a != null && a instanceof aaa' is always 'false'"><warning descr="Condition 'a != null' is always 'true'">a != null</warning> && <warning descr="Condition 'a instanceof aaa' is always 'false' when reached">a instanceof aaa</warning></warning>) {
if (<warning descr="Condition is always true">true</warning>) {
//a = new aaa();
}
@@ -1,4 +1,10 @@
class X {
void test() {
Object obj1 = 100000L;
Object obj2 = 100000L;
if(obj1 == obj2) {}
}
public static void main(String[] args) {
int primitive = 1024;
Object object = primitive;
@@ -90,4 +90,10 @@ class StringEquality {
}
}
}
void testObject() {
Object x = " foo ".trim();
Object y = " foo ".trim();
if (x == y) {}
}
}