fixed wrong dfa for integer comparisons (IDEA-91380)

This commit is contained in:
peter
2012-09-12 10:36:19 +02:00
parent 7661418e8b
commit 4671577a1a
7 changed files with 83 additions and 37 deletions
@@ -952,9 +952,6 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
if (JavaTokenType.PLUS == op && (type == null || !type.equalsToText(CommonClassNames.JAVA_LANG_STRING))) {
return null;
}
else if (op == JavaTokenType.LT || op == JavaTokenType.GT) {
return JavaTokenType.NE;
}
return op;
}
@@ -553,7 +553,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (dfaCond instanceof DfaUnboxedValue) {
DfaVariableValue dfaVar = ((DfaUnboxedValue)dfaCond).getVariable();
boolean isNegated = dfaVar.isNegated();
DfaVariableValue dfaNormalVar = isNegated ? (DfaVariableValue)dfaVar.createNegated() : dfaVar;
DfaVariableValue dfaNormalVar = isNegated ? dfaVar.createNegated() : dfaVar;
DfaConstValue dfaTrue = myFactory.getConstFactory().getTrue();
final DfaValue boxedTrue = myFactory.getBoxedFactory().createBoxed(dfaTrue);
DfaRelationValue dfaEqualsTrue = myFactory.getRelationFactory().createRelation(dfaNormalVar, boxedTrue, JavaTokenType.EQEQ, isNegated);
@@ -563,7 +563,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (dfaCond instanceof DfaVariableValue) {
DfaVariableValue dfaVar = (DfaVariableValue)dfaCond;
boolean isNegated = dfaVar.isNegated();
DfaVariableValue dfaNormalVar = isNegated ? (DfaVariableValue)dfaVar.createNegated() : dfaVar;
DfaVariableValue dfaNormalVar = isNegated ? dfaVar.createNegated() : dfaVar;
DfaConstValue dfaTrue = myFactory.getConstFactory().getTrue();
DfaRelationValue dfaEqualsTrue = myFactory.getRelationFactory().createRelation(dfaNormalVar, dfaTrue, JavaTokenType.EQEQ, isNegated);
@@ -576,7 +576,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (!(dfaCond instanceof DfaRelationValue)) return true;
DfaRelationValue dfaRelation = (DfaRelationValue)dfaCond;
return applyRelationCondition((DfaRelationValue)dfaCond);
}
private boolean applyRelationCondition(DfaRelationValue dfaRelation) {
DfaValue dfaLeft = dfaRelation.getLeftOperand();
DfaValue dfaRight = dfaRelation.getRightOperand();
if (dfaRight == null || dfaLeft == null) return false;
@@ -610,6 +613,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (dfaLeft instanceof DfaUnknownValue || dfaRight instanceof DfaUnknownValue) return true;
return applyEquivalenceRelation(dfaRelation, dfaLeft, dfaRight);
}
private boolean applyEquivalenceRelation(DfaRelationValue dfaRelation, DfaValue dfaLeft, DfaValue dfaRight) {
boolean isNegated = dfaRelation.isNonEquality();
if (!isNegated && !dfaRelation.isEquality()) {
return true;
}
boolean result = applyRelation(dfaLeft, dfaRight, isNegated);
if (dfaRight instanceof DfaConstValue) {
Object constVal = ((DfaConstValue)dfaRight).getValue();
@@ -34,20 +34,19 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import static com.intellij.psi.JavaTokenType.*;
public class BinopInstruction extends BranchingInstruction {
private static final TokenSet ourSignificantOperations = TokenSet.create(EQEQ, NE, LT, GT, LE, GE, INSTANCEOF_KEYWORD, PLUS);
private final IElementType myOperationSign;
private final Project myProject;
public BinopInstruction(IElementType opSign, PsiElement psiAnchor, @NotNull Project project) {
myProject = project;
if (JavaTokenType.EQEQ == opSign || JavaTokenType.NE == opSign || JavaTokenType.INSTANCEOF_KEYWORD == opSign || JavaTokenType.PLUS == opSign) {
myOperationSign = opSign;
}
else {
myOperationSign = null;
}
myOperationSign = ourSignificantOperations.contains(opSign) ? opSign : null;
setPsiAnchor(psiAnchor);
}
@@ -70,8 +70,8 @@ public abstract class BranchingInstruction extends Instruction {
return "true".equals(text) || "false".equals(text);
}
protected void setPsiAnchor(PsiElement psiAcnchor) {
myExpression = psiAcnchor;
isConstTrue = psiAcnchor != null && isBoolConst(psiAcnchor);
protected void setPsiAnchor(PsiElement psiAnchor) {
myExpression = psiAnchor;
isConstTrue = psiAnchor != null && isBoolConst(psiAnchor);
}
}
@@ -25,7 +25,6 @@
package com.intellij.codeInspection.dataFlow.value;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
@@ -33,6 +32,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import static com.intellij.psi.JavaTokenType.*;
public class DfaRelationValue extends DfaValue {
private DfaValue myLeftOperand;
private DfaValue myRightOperand;
@@ -52,8 +53,8 @@ public class DfaRelationValue extends DfaValue {
@Nullable
public DfaRelationValue createRelation(DfaValue dfaLeft, DfaValue dfaRight, IElementType relation, boolean negated) {
if (dfaRight instanceof DfaTypeValue && JavaTokenType.INSTANCEOF_KEYWORD != relation) return null;
if (JavaTokenType.PLUS == relation) return null;
if (dfaRight instanceof DfaTypeValue && INSTANCEOF_KEYWORD != relation) return null;
if (PLUS == relation) return null;
if (dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue
|| dfaRight instanceof DfaVariableValue || dfaRight instanceof DfaBoxedValue || dfaRight instanceof DfaUnboxedValue) {
@@ -79,16 +80,16 @@ public class DfaRelationValue extends DfaValue {
final DfaValue dfaLeft,
final DfaValue dfaRight) {
// To canonical form.
if (JavaTokenType.NE == relation) {
relation = JavaTokenType.EQEQ;
if (NE == relation) {
relation = EQEQ;
negated = !negated;
}
else if (JavaTokenType.LT == relation) {
relation = JavaTokenType.GE;
else if (LT == relation) {
relation = GE;
negated = !negated;
}
else if (JavaTokenType.LE == relation) {
relation = JavaTokenType.GT;
else if (LE == relation) {
relation = GT;
negated = !negated;
}
@@ -115,19 +116,10 @@ public class DfaRelationValue extends DfaValue {
}
private static IElementType getSymmetricOperation(IElementType sign) {
if (JavaTokenType.LT == sign) {
return JavaTokenType.GT;
}
else if (JavaTokenType.GE == sign) {
return JavaTokenType.LE;
}
else if (JavaTokenType.GT == sign) {
return JavaTokenType.LT;
}
else if (JavaTokenType.LE == sign) {
return JavaTokenType.GE;
}
if (LT == sign) return GT;
if (GE == sign) return LE;
if (GT == sign) return LT;
if (LE == sign) return GE;
return sign;
}
}
@@ -168,6 +160,14 @@ public class DfaRelationValue extends DfaValue {
rel.myIsNegated == myIsNegated;
}
public boolean isEquality() {
return myRelation == EQEQ && !myIsNegated;
}
public boolean isNonEquality() {
return myRelation == EQEQ && myIsNegated || myRelation == GT && !myIsNegated || myRelation == GE && myIsNegated;
}
@NonNls public String toString() {
return (isNegated() ? "not " : "") + myLeftOperand + " " + myRelation + " " + myRightOperand;
}
@@ -0,0 +1,38 @@
import org.jetbrains.annotations.NotNull;
import java.io.File;
class Zoo2 {
public static boolean startsWith(@NotNull String path, @NotNull String start, final boolean caseSensitive) {
final int length1 = path.length();
final int length2 = start.length();
if (length2 == 0) return true;
if (length2 > length1) return false;
if (!path.regionMatches(!caseSensitive, 0, start, 0, length2)) return false;
if (length1 == length2) return true;
char last2 = start.charAt(length2 - 1);
char next1;
if (last2 == '/' || last2 == File.separatorChar) {
next1 = path.charAt(length2 - 1);
}
else {
next1 = path.charAt(length2);
}
return next1 == '/' || next1 == File.separatorChar;
}
void foo(Some me, Some other) {
if (me.depth < other.depth) {
System.out.println("less");
} else if (other.depth > me.depth) {
System.out.println("more");
}
}
}
class Some {
final int depth;
Some(int depth) {
this.depth = depth;
}
}
@@ -77,6 +77,7 @@ public class DataFlowInspectionFixtureTest extends JavaCodeInsightFixtureTestCas
public void testEqualsConstant() throws Throwable { doTest(); }
public void testFinalLoopVariableInstanceof() throws Throwable { doTest(); }
public void testGreaterIsNotEquals() throws Throwable { doTest(); }
public void testNotGreaterIsNotEquals() throws Throwable { doTest(); }
public void testChainedFinalFieldsDfa() throws Throwable { doTest(); }
public void testChainedFinalFieldAccessorsDfa() throws Throwable { doTest(); }