diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 53c2810fb8b6..003f660c4907 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -20,7 +20,6 @@ import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInspection.dataFlow.inliner.*; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.*; -import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; @@ -883,23 +882,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { ifNoException.setOffset(myCurrentFlow.getInstructionCount()); } - private static class ApplyNotNullInstruction extends Instruction { - @Override - public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState state, InstructionVisitor visitor) { - DfaValue value = state.pop(); - DfaValueFactory factory = runner.getFactory(); - if (state.applyCondition(factory.createCondition(value, RelationType.NE, factory.getConstFactory().getNull()))) { - return nextInstruction(runner, state); - } - return DfaInstructionState.EMPTY_ARRAY; - } - - @Override - public String toString() { - return "APPLY NOT NULL"; - } - } - @Override public void visitTryStatement(PsiTryStatement statement) { startElement(statement); @@ -1499,10 +1481,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { JavaResolveResult result = methodExpression.advancedResolve(false); PsiElement method = result.getElement(); PsiParameter[] parameters = method instanceof PsiMethod ? ((PsiMethod)method).getParameterList().getParameters() : null; - boolean isEqualsCall = expressions.length == 1 && method instanceof PsiMethod && - "equals".equals(((PsiMethod)method).getName()) && parameters.length == 1 && - parameters[0].getType().equalsToText(JAVA_LANG_OBJECT) && - PsiType.BOOLEAN.equals(((PsiMethod)method).getReturnType()); for (int i = 0; i < expressions.length; i++) { PsiExpression paramExpr = expressions[i]; @@ -1510,30 +1488,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { if (parameters != null && i < parameters.length) { generateBoxingUnboxingInstructionFor(paramExpr, result.getSubstitutor().substitute(parameters[i].getType())); } - if (i == 0 && isEqualsCall) { - // stack: .., qualifier, arg1 - addInstruction(new SpliceInstruction(2, 0, 1, 0)); - // stack: .., arg1, qualifier, arg1 - } } addBareCall(expression, expression.getMethodExpression()); - - if (isEqualsCall) { - // assume equals argument must be not-null if the result is true - // don't assume the call result to be false if arg1==null - - // stack: .., arg1, call-result - ConditionalGotoInstruction ifFalse = addInstruction(new ConditionalGotoInstruction(null, true, null)); - - addInstruction(new ApplyNotNullInstruction()); - addInstruction(new PushInstruction(myFactory.getConstFactory().getTrue(), null)); - addInstruction(new GotoInstruction(getEndOffset(expression))); - - ifFalse.setOffset(myCurrentFlow.getInstructionCount()); - addInstruction(new PopInstruction()); - addInstruction(new PushInstruction(myFactory.getConstFactory().getFalse(), null)); - } finishElement(expression); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java index 75f37ed6a529..1abee110b0a9 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java @@ -109,11 +109,7 @@ public class CustomMethodHandlers { if (leftConst != null && rightConst != null) { return singleResult(memState, factory.getBoolean(ignoreCase ? leftConst.equalsIgnoreCase(rightConst) : leftConst.equals(rightConst))); } - DfaValue leftLength = SpecialField.STRING_LENGTH.createValue(factory, args.myQualifier); - DfaValue rightLength = SpecialField.STRING_LENGTH.createValue(factory, arg); - DfaValue trueRelation = factory.createCondition(leftLength, RelationType.EQ, rightLength); - DfaValue falseRelation = factory.createCondition(leftLength, RelationType.NE, rightLength); - return applyCondition(memState, trueRelation, DfaUnknownValue.getInstance(), falseRelation, factory.getBoolean(false)); + return Collections.emptyList(); } private static List indexOf(DfaValue qualifier, diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/HardcodedContracts.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/HardcodedContracts.java index 5386febd8d72..944fbbe646e5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/HardcodedContracts.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/HardcodedContracts.java @@ -110,6 +110,11 @@ public class HardcodedContracts { else if ("isEmpty".equals(methodName) && paramCount == 0) { return SpecialField.STRING_LENGTH.getEmptyContracts(); } + else if (("equals".equals(methodName) || "equalsIgnoreCase".equals(methodName)) && paramCount == 1) { + return Arrays.asList(getEqualsContract(), MethodContract.singleConditionContract( + ContractValue.qualifier().specialField(SpecialField.STRING_LENGTH), RelationType.NE, + ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), FALSE_VALUE)); + } } else if (MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_COLLECTION, PsiType.BOOLEAN, "isEmpty")) { return SpecialField.COLLECTION_SIZE.getEmptyContracts(); @@ -120,7 +125,7 @@ public class HardcodedContracts { } else if (MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_SET, PsiType.BOOLEAN, "equals", (PsiType)null) || MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_LIST, PsiType.BOOLEAN, "equals", (PsiType)null)) { - return Collections.singletonList(MethodContract.singleConditionContract( + return Arrays.asList(getEqualsContract(), MethodContract.singleConditionContract( ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.NE, ContractValue.argument(0).specialField(SpecialField.COLLECTION_SIZE), FALSE_VALUE)); } @@ -141,7 +146,7 @@ public class HardcodedContracts { ContractValue.qualifier().specialField(SpecialField.MAP_SIZE), RelationType.EQ, ContractValue.zero(), FALSE_VALUE)); } else if (MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_MAP, PsiType.BOOLEAN, "equals", (PsiType)null)) { - return Collections.singletonList(MethodContract.singleConditionContract( + return Arrays.asList(getEqualsContract(), MethodContract.singleConditionContract( ContractValue.qualifier().specialField(SpecialField.MAP_SIZE), RelationType.NE, ContractValue.argument(0).specialField(SpecialField.MAP_SIZE), FALSE_VALUE)); } @@ -176,10 +181,18 @@ public class HardcodedContracts { return Arrays.asList(optionalAbsentContract(FALSE_VALUE), MethodContract.trivialContract(TRUE_VALUE)); } } + else if (MethodUtils.isEquals(method)) { + return Collections.singletonList(getEqualsContract()); + } return Collections.emptyList(); } + @NotNull + private static StandardMethodContract getEqualsContract() { + return new StandardMethodContract(new MethodContract.ValueConstraint[] {NULL_VALUE}, FALSE_VALUE); + } + static MethodContract optionalAbsentContract(MethodContract.ValueConstraint returnValue) { return MethodContract .singleConditionContract(ContractValue.qualifier(), RelationType.IS, ContractValue.optionalValue(false), returnValue); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 0c93bf624c60..b9b47ec5e85a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -324,15 +324,10 @@ public class StandardInstructionVisitor extends InstructionVisitor { private List handleKnownMethods(MethodCallInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { CustomMethodHandlers.CustomMethodHandler handler = CustomMethodHandlers.find(instruction); if (handler == null) return Collections.emptyList(); + memState = memState.createCopy(); DfaCallArguments callArguments = popCall(instruction, runner, memState, false); - List states = - callArguments.myArguments == null ? Collections.emptyList() : - handler.handle(callArguments, memState, runner.getFactory()); - if (states.isEmpty()) { - memState.push(getMethodResultValue(instruction, callArguments.myQualifier, memState, runner.getFactory())); - return Collections.singletonList(memState); - } - return states; + return callArguments.myArguments == null ? Collections.emptyList() : + handler.handle(callArguments, memState, runner.getFactory()); } @NotNull