@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; }
@Override public DfaInstructionState[] visitMethodCall( final MethodCallInstruction instruction, final DataFlowRunner runner, final DfaMemoryState memState) { DfaValue[] argValues = popCallArguments(instruction, runner, memState); final DfaValue qualifier = popQualifier(instruction, runner, memState); List<DfaMemoryState> currentStates = ContainerUtil.newArrayList(memState); Set<DfaMemoryState> finalStates = ContainerUtil.newLinkedHashSet(); if (argValues != null) { for (MethodContract contract : instruction.getContracts()) { currentStates = addContractResults( argValues, contract, currentStates, instruction, runner.getFactory(), finalStates); } } for (DfaMemoryState state : currentStates) { state.push(getMethodResultValue(instruction, qualifier, runner.getFactory())); finalStates.add(state); } return ContainerUtil.map2Array( finalStates, DfaInstructionState.class, new Function<DfaMemoryState, DfaInstructionState>() { @Override public DfaInstructionState fun(DfaMemoryState state) { if (instruction.shouldFlushFields()) { state.flushFields(); } return new DfaInstructionState( runner.getInstruction(instruction.getIndex() + 1), state); } }); }