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 9ec332a8405b..9e6ea841a280 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -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; } 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 3ba99012a81e..2ba233ea60ab 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -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(); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java index 5e13d70118f2..195f538da745 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java @@ -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); } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java index 2a036c3256d8..d1524fc42092 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java @@ -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); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java index 6b96b0bba706..2e09163b00ed 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java @@ -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; } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/NotGreaterIsNotEquals.java b/java/java-tests/testData/inspection/dataFlow/fixture/NotGreaterIsNotEquals.java new file mode 100644 index 000000000000..6528fcd5396d --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/NotGreaterIsNotEquals.java @@ -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; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java index 0e7f4ec099c0..a5f80d7392b2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java @@ -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(); }