boolean (@NotNull CFGBuilder builder, @NotNull PsiMethodCallExpression call) { if (MAP_COMPUTE.test(call)) { PsiExpression qualifier = call.getMethodExpression().getQualifierExpression(); if (qualifier == null) return false; PsiType type = call.getType(); if (type == null) return false; PsiExpression[] args = call.getArgumentList().getExpressions(); PsiExpression key = args[0]; PsiExpression function = args[1]; builder .pushExpression(qualifier) // stack: .. qualifier .ensure(RelationType.IS, Mutability.MUTABLE.asDfType(), new MutabilityProblem(call, true), null) .pushExpression(key) // stack: .. qualifier; key .boxUnbox(key, PsiUtil.substituteTypeParameter(qualifier.getType(), CommonClassNames.JAVA_UTIL_MAP, 0, true)) .evaluateFunction(function); String name = Objects.requireNonNull(call.getMethodExpression().getReferenceName()); switch (name) { case "computeIfAbsent" -> inlineComputeIfAbsent(builder, function, type); case "computeIfPresent" -> inlineComputeIfPresent(builder, function, type); case "compute" -> inlineCompute(builder, function, type); default -> throw new IllegalStateException("Unsupported name: " + name); } builder.resultOf(call); return true; } if (MAP_MERGE.test(call)) { PsiExpression qualifier = call.getMethodExpression().getQualifierExpression(); if (qualifier == null) return false; PsiType type = call.getType(); if (type == null) return false; PsiExpression[] args = call.getArgumentList().getExpressions(); PsiExpression key = args[0]; PsiExpression value = args[1]; PsiExpression function = args[2]; builder .pushExpression(qualifier) // stack: .. qualifier .ensure(RelationType.IS, Mutability.MUTABLE.asDfType(), new MutabilityProblem(call, true), null) .pushExpression(key) // stack: .. qualifier; key .pop() // stack: .. qualifier .pushExpression(value) // stack: .. qualifier; value .boxUnbox(value, ExpectedTypeUtils.findExpectedType(value, false)) .evaluateFunction(function) .pushUnknown() // stack: .. qualifier; value; get() result .ifNotNull() // stack: .. qualifier; value .push(DfTypes.typedObject(type, Nullability.NOT_NULL)) // stack: .. qualifier; value; get() result .swap() // stack: .. qualifier; get() result; value .invokeFunction(2, function) // stack: .. qualifier; mapping result .end() .chain(b -> flushSize(b)) .resultOf(call); return true; } return false; }