From 304d46bb965356c6aa2a880b41355b00b3de0ec2 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 17 Apr 2012 17:06:25 +0200 Subject: [PATCH] don't multiply dfa states up to infinity when comparing ints (NameUtil.MinusculeMatcher.matchAfterFragment too complex to analyze) --- .../dataFlow/DfaMemoryStateImpl.java | 60 +++++++++++-------- .../fixture/TernaryInWhileNotComplex.java | 25 ++++++++ .../DataFlowInspectionFixtureTest.java | 1 + 3 files changed, 62 insertions(+), 24 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/TernaryInWhileNotComplex.java 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 2b4005a40ef8..82a0cc5358c3 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -297,9 +297,13 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } } - private int getOrCreateEqClassIndex(DfaValue dfaValue) { + @Nullable("for boxed values which can't be compared by ==") + private Integer getOrCreateEqClassIndex(DfaValue dfaValue) { int i = getEqClassIndex(dfaValue); if (i != -1) return i; + if (!canBeReused(dfaValue) && !(((DfaBoxedValue)dfaValue).getWrappedValue() instanceof DfaConstValue)) { + return null; + } SortedIntSet aClass = new SortedIntSet(); aClass.add(dfaValue.getID()); myEqClasses.add(aClass); @@ -338,26 +342,28 @@ public class DfaMemoryStateImpl implements DfaMemoryState { for (int i = 0; i < myEqClasses.size(); i++) { SortedIntSet aClass = myEqClasses.get(i); if (aClass != null && aClass.contains(dfaValue.getID())) { - if (dfaValue instanceof DfaBoxedValue && !canBeReused(((DfaBoxedValue)dfaValue).getWrappedValue(), this) && aClass.size() > 1) return -1; + if (!canBeReused(dfaValue) && aClass.size() > 1) return -1; return i; } } return -1; } - private static boolean canBeReused(final DfaValue valueToWrap, final DfaMemoryState memoryState) { - if (valueToWrap instanceof DfaConstValue) { - return cacheable((DfaConstValue)valueToWrap); - } - else if (valueToWrap instanceof DfaVariableValue) { - if (PsiType.BOOLEAN.equals(((DfaVariableValue)valueToWrap).getPsiVariable().getType())) return true; - List values = ((DfaMemoryStateImpl)memoryState).getEqClassesFor(valueToWrap); - for (DfaValue value : values) { - if (value instanceof DfaConstValue && cacheable((DfaConstValue)value)) return true; + + private boolean canBeReused(final DfaValue dfaValue) { + if (dfaValue instanceof DfaBoxedValue) { + DfaValue valueToWrap = ((DfaBoxedValue)dfaValue).getWrappedValue(); + if (valueToWrap instanceof DfaConstValue) { + return cacheable((DfaConstValue)valueToWrap); + } + if (valueToWrap instanceof DfaVariableValue) { + if (PsiType.BOOLEAN.equals(((DfaVariableValue)valueToWrap).getPsiVariable().getType())) return true; + for (DfaValue value : getEqClassesFor(valueToWrap)) { + if (value instanceof DfaConstValue && cacheable((DfaConstValue)value)) return true; + } } return false; } - return false; - //throw new IllegalArgumentException(""+valueToWrap); + return true; } private static boolean cacheable(DfaConstValue dfaConstValue) { @@ -474,10 +480,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (dfaValue instanceof DfaVariableValue || dfaValue instanceof DfaConstValue) { DfaConstValue dfaNull = myFactory.getConstFactory().getNull(); - int c1Index = getOrCreateEqClassIndex(dfaValue); - int c2Index = getOrCreateEqClassIndex(dfaNull); + Integer c1Index = getOrCreateEqClassIndex(dfaValue); + Integer c2Index = getOrCreateEqClassIndex(dfaNull); - return c1Index == c2Index; + return c1Index != null && c1Index.equals(c2Index); } return false; @@ -485,13 +491,16 @@ public class DfaMemoryStateImpl implements DfaMemoryState { public boolean isNotNull(DfaVariableValue dfaVar) { DfaConstValue dfaNull = myFactory.getConstFactory().getNull(); - int c1Index = getOrCreateEqClassIndex(dfaVar); - int c2Index = getOrCreateEqClassIndex(dfaNull); + Integer c1Index = getOrCreateEqClassIndex(dfaVar); + Integer c2Index = getOrCreateEqClassIndex(dfaNull); + if (c1Index == null || c2Index == null) { + return false; + } long[] pairs = myDistinctClasses.toArray(); for (long pair : pairs) { - if (low(pair) == c1Index && high(pair) == c2Index || - high(pair) == c1Index && low(pair) == c2Index) { + if (c1Index.equals(low(pair)) && c2Index.equals(high(pair)) || + c1Index.equals(high(pair)) && c2Index.equals(low(pair))) { return true; } } @@ -637,15 +646,18 @@ public class DfaMemoryStateImpl implements DfaMemoryState { private boolean applyRelation(@NotNull final DfaValue dfaLeft, @NotNull final DfaValue dfaRight, boolean isNegated) { // DfaConstValue || DfaVariableValue - int c1Index = getOrCreateEqClassIndex(dfaLeft); - int c2Index = getOrCreateEqClassIndex(dfaRight); + Integer c1Index = getOrCreateEqClassIndex(dfaLeft); + Integer c2Index = getOrCreateEqClassIndex(dfaRight); + if (c1Index == null || c2Index == null) { + return true; + } if (!isNegated) { //Equals - if (c1Index == c2Index) return true; + if (c1Index.equals(c2Index)) return true; if (!uniteClasses(c1Index, c2Index)) return false; } else { // Not Equals - if (c1Index == c2Index) return false; + if (c1Index.equals(c2Index)) return false; makeClassesDistinct(c1Index, c2Index); } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/TernaryInWhileNotComplex.java b/java/java-tests/testData/inspection/dataFlow/fixture/TernaryInWhileNotComplex.java new file mode 100644 index 000000000000..a1b2affe100e --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/TernaryInWhileNotComplex.java @@ -0,0 +1,25 @@ +import java.util.List; + +public class Foo { + public void matchAfterFragment(int patternIndex, int matchLen) { + int star = patternIndex < matchLen ? matchLen : -1; + while (matchLen > 0) { + int i = matchLen == star ? matchLen : star; + } + } + + public void matchAfterFragmentBoxed(Integer patternIndex, Integer matchLen) { + Integer star = patternIndex < matchLen ? matchLen : -1; + while (matchLen > 0) { + Integer i = matchLen == star ? matchLen : star; + } + } + + public void matchAfterFragmentSemiBoxed(Integer patternIndex, Integer matchLen) { + int star = patternIndex < matchLen ? matchLen : -1; + while (matchLen > 0) { + Integer i = matchLen == star ? matchLen : star; + } + } + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java index a4b7ec1fe242..22407c7359ce 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionFixtureTest.java @@ -53,4 +53,5 @@ public class DataFlowInspectionFixtureTest extends JavaCodeInsightFixtureTestCas /*public void testAnnReport() throws Throwable { doTest(); }*/ public void testBigMethodNotComplex() throws Throwable { doTest(); } + public void testTernaryInWhileNotComplex() throws Throwable { doTest(); } }