@Override public DfaInstructionState[] visitBinop( BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { myReachable.add(instruction); DfaValue dfaRight = memState.pop(); DfaValue dfaLeft = memState.pop(); final IElementType opSign = instruction.getOperationSign(); if (opSign != null) { DfaInstructionState[] states = handleConstantComparison(instruction, runner, memState, dfaRight, dfaLeft, opSign); if (states == null) { states = handleRelationBinop(instruction, runner, memState, dfaRight, dfaLeft); } if (states != null) { return states; } if (PLUS == opSign) { memState.push(instruction.getNonNullStringValue(runner.getFactory())); } else { if (instruction instanceof InstanceofInstruction) { handleInstanceof((InstanceofInstruction) instruction, dfaRight, dfaLeft); } memState.push(DfaUnknownValue.getInstance()); } } else { memState.push(DfaUnknownValue.getInstance()); } instruction.setTrueReachable(); // Not a branching instruction actually. instruction.setFalseReachable(); return nextInstruction(instruction, runner, memState); }
@NotNull private DfaValue getMethodResultValue( MethodCallInstruction instruction, @Nullable DfaValue qualifierValue, DfaValueFactory factory) { DfaValue precalculated = instruction.getPrecalculatedReturnValue(); if (precalculated != null) { return precalculated; } final PsiType type = instruction.getResultType(); final MethodCallInstruction.MethodType methodType = instruction.getMethodType(); if (methodType == MethodCallInstruction.MethodType.UNBOXING) { return factory.getBoxedFactory().createUnboxed(qualifierValue); } if (methodType == MethodCallInstruction.MethodType.BOXING) { DfaValue boxed = factory.getBoxedFactory().createBoxed(qualifierValue); return boxed == null ? factory.createTypeValue(type, Nullness.NOT_NULL) : boxed; } if (methodType == MethodCallInstruction.MethodType.CAST) { assert qualifierValue != null; if (qualifierValue instanceof DfaConstValue) { Object casted = TypeConversionUtil.computeCastTo(((DfaConstValue) qualifierValue).getValue(), type); return factory .getConstFactory() .createFromValue(casted, type, ((DfaConstValue) qualifierValue).getConstant()); } return qualifierValue; } if (type != null && (type instanceof PsiClassType || type.getArrayDimensions() > 0)) { Nullness nullability = myReturnTypeNullability.get(instruction); if (nullability == Nullness.UNKNOWN && factory.isUnknownMembersAreNullable()) { nullability = Nullness.NULLABLE; } return factory.createTypeValue(type, nullability); } return DfaUnknownValue.getInstance(); }
@Nullable private DfaValue[] popCallArguments( MethodCallInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { final PsiExpression[] args = instruction.getArgs(); PsiMethod method = instruction.getTargetMethod(); boolean varargCall = instruction.isVarArgCall(); DfaValue[] argValues; if (method == null || instruction.getContracts().isEmpty()) { argValues = null; } else { int paramCount = method.getParameterList().getParametersCount(); if (paramCount == args.length || method.isVarArgs() && args.length >= paramCount - 1) { argValues = new DfaValue[paramCount]; if (varargCall) { argValues[paramCount - 1] = DfaUnknownValue.getInstance(); } } else { argValues = null; } } for (int i = 0; i < args.length; i++) { final DfaValue arg = memState.pop(); int paramIndex = args.length - i - 1; if (argValues != null && (paramIndex < argValues.length - 1 || !varargCall)) { argValues[paramIndex] = arg; } PsiExpression expr = args[paramIndex]; Nullness requiredNullability = instruction.getArgRequiredNullability(expr); if (requiredNullability == Nullness.NOT_NULL) { if (!checkNotNullable( memState, arg, NullabilityProblem.passingNullableToNotNullParameter, expr)) { forceNotNull(runner, memState, arg); } } else if (requiredNullability == Nullness.UNKNOWN) { checkNotNullable( memState, arg, NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter, expr); } } return argValues; }