private boolean applyEquivalenceRelation( @NotNull DfaRelationValue dfaRelation, DfaValue dfaLeft, DfaValue dfaRight) { boolean isNegated = dfaRelation.isNonEquality(); if (!isNegated && !dfaRelation.isEquality()) { return true; } final boolean containsCalls = dfaLeft instanceof DfaVariableValue && ((DfaVariableValue) dfaLeft).containsCalls(); // track "x" property state only inside "if (getX() != null) ..." if (containsCalls && !isNotNull(dfaLeft) && isNull(dfaRight) && !isNegated) { return true; } if (dfaLeft == dfaRight) { return containsCalls || !isNegated; } if (isNull(dfaLeft) && isNotNull(dfaRight) || isNull(dfaRight) && isNotNull(dfaLeft)) { return isNegated; } if (!isNegated) { if (dfaLeft instanceof DfaVariableValue) { updateVarStateOnComparison((DfaVariableValue) dfaLeft, dfaRight); } if (dfaRight instanceof DfaVariableValue) { updateVarStateOnComparison((DfaVariableValue) dfaRight, dfaLeft); } } if (!applyRelation(dfaLeft, dfaRight, isNegated)) { return false; } if (!checkCompareWithBooleanLiteral(dfaLeft, dfaRight, isNegated)) { return false; } if (dfaLeft instanceof DfaVariableValue) { if (!applyUnboxedRelation((DfaVariableValue) dfaLeft, dfaRight, isNegated)) { return false; } if (!applyBoxedRelation((DfaVariableValue) dfaLeft, dfaRight, isNegated)) { return false; } } return true; }
@Override public boolean applyInstanceofOrNull(@NotNull DfaRelationValue dfaCond) { DfaValue left = unwrap(dfaCond.getLeftOperand()); if (!(left instanceof DfaVariableValue)) return true; DfaVariableValue dfaVar = (DfaVariableValue) left; DfaTypeValue dfaType = (DfaTypeValue) dfaCond.getRightOperand(); if (isUnknownState(dfaVar) || isNull(dfaVar)) return true; DfaVariableState newState = getVariableState(dfaVar).withInstanceofValue(dfaType); if (newState != null) { setVariableState(dfaVar, newState); return true; } return false; }
@Nullable private DfaInstructionState[] handleRelationBinop( BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState, DfaValue dfaRight, DfaValue dfaLeft) { DfaValueFactory factory = runner.getFactory(); final Instruction next = runner.getInstruction(instruction.getIndex() + 1); DfaRelationValue dfaRelation = factory .getRelationFactory() .createRelation(dfaLeft, dfaRight, instruction.getOperationSign(), false); if (dfaRelation == null) { return null; } myCanBeNullInInstanceof.add(instruction); ArrayList<DfaInstructionState> states = new ArrayList<DfaInstructionState>(); final DfaMemoryState trueCopy = memState.createCopy(); if (trueCopy.applyCondition(dfaRelation)) { trueCopy.push(factory.getConstFactory().getTrue()); instruction.setTrueReachable(); states.add(new DfaInstructionState(next, trueCopy)); } //noinspection UnnecessaryLocalVariable DfaMemoryState falseCopy = memState; if (falseCopy.applyCondition(dfaRelation.createNegated())) { falseCopy.push(factory.getConstFactory().getFalse()); instruction.setFalseReachable(); states.add(new DfaInstructionState(next, falseCopy)); if (instruction instanceof InstanceofInstruction && !falseCopy.isNull(dfaLeft)) { myUsefulInstanceofs.add((InstanceofInstruction) instruction); } } return states.toArray(new DfaInstructionState[states.size()]); }
@Nullable private static DfaInstructionState[] handleConstantComparison( BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState, DfaValue dfaRight, DfaValue dfaLeft, IElementType opSign) { if (dfaRight instanceof DfaConstValue && dfaLeft instanceof DfaVariableValue) { Object value = ((DfaConstValue) dfaRight).getValue(); if (value instanceof Number) { DfaInstructionState[] result = checkComparingWithConstant( instruction, runner, memState, (DfaVariableValue) dfaLeft, opSign, ((Number) value).doubleValue()); if (result != null) { return result; } } } if (dfaRight instanceof DfaVariableValue && dfaLeft instanceof DfaConstValue) { return handleConstantComparison( instruction, runner, memState, dfaLeft, dfaRight, DfaRelationValue.getSymmetricOperation(opSign)); } if (EQEQ != opSign && NE != opSign) { return null; } if (dfaLeft instanceof DfaConstValue && dfaRight instanceof DfaConstValue || dfaLeft == runner.getFactory().getConstFactory().getContractFail() || dfaRight == runner.getFactory().getConstFactory().getContractFail()) { boolean negated = (NE == opSign) ^ (DfaMemoryStateImpl.isNaN(dfaLeft) || DfaMemoryStateImpl.isNaN(dfaRight)); if (dfaLeft == dfaRight ^ negated) { return alwaysTrue(instruction, runner, memState); } return alwaysFalse(instruction, runner, memState); } return null; }
private boolean applyRelationCondition(@NotNull DfaRelationValue dfaRelation) { DfaValue dfaLeft = dfaRelation.getLeftOperand(); DfaValue dfaRight = dfaRelation.getRightOperand(); if (dfaLeft instanceof DfaUnknownValue || dfaRight instanceof DfaUnknownValue) return true; boolean isNegated = dfaRelation.isNegated(); if (dfaLeft instanceof DfaTypeValue && ((DfaTypeValue) dfaLeft).isNotNull() && dfaRight == myFactory.getConstFactory().getNull()) { return isNegated; } if (dfaRight instanceof DfaTypeValue) { if (dfaLeft instanceof DfaVariableValue) { DfaVariableValue dfaVar = (DfaVariableValue) dfaLeft; if (isUnknownState(dfaVar)) return true; if (!dfaRelation.isInstanceOf()) { if (((DfaTypeValue) dfaRight).isNotNull() && isNull(dfaVar)) { return isNegated; } return true; } if (isNegated) { DfaVariableState newState = getVariableState(dfaVar).withNotInstanceofValue((DfaTypeValue) dfaRight); if (newState != null) { setVariableState(dfaVar, newState); return true; } return !getVariableState(dfaVar).isNotNull() && applyRelation(dfaVar, myFactory.getConstFactory().getNull(), false); } if (applyRelation(dfaVar, myFactory.getConstFactory().getNull(), true)) { DfaVariableState newState = getVariableState(dfaVar).withInstanceofValue((DfaTypeValue) dfaRight); if (newState != null) { setVariableState(dfaVar, newState); return true; } } return false; } return true; } if (isEffectivelyNaN(dfaLeft) || isEffectivelyNaN(dfaRight)) { applyEquivalenceRelation(dfaRelation, dfaLeft, dfaRight); return isNegated; } if (canBeNaN(dfaLeft) && canBeNaN(dfaRight)) { if (dfaLeft == dfaRight && dfaLeft instanceof DfaVariableValue && !(((DfaVariableValue) dfaLeft).getVariableType() instanceof PsiPrimitiveType)) { return !isNegated; } applyEquivalenceRelation(dfaRelation, dfaLeft, dfaRight); return true; } return applyEquivalenceRelation(dfaRelation, dfaLeft, dfaRight); }