void (PsiMethodCallExpression call) { boolean voidContext = ExpressionUtils.isVoidContext(call); String name = call.getMethodExpression().getReferenceName(); boolean queryQualifier = isQueryUpdateMethodName(name, myQueryNames); boolean updateQualifier = isQueryUpdateMethodName(name, myUpdateNames); if (queryQualifier && (!voidContext || PsiTypes.voidType().equals(call.getType()) || "toArray".equals(name) && !call.getArgumentList().isEmpty())) { makeQueried(); } if (updateQualifier) { makeUpdated(); if (!voidContext) { makeQueried(); } else { for (PsiExpression arg : call.getArgumentList().getExpressions()) { PsiParameter parameter = MethodCallUtils.getParameterForArgument(arg); if (parameter != null && LambdaUtil.isFunctionalType(parameter.getType())) { if (ExpressionUtils.nonStructuralChildren(arg).anyMatch(e -> mayHaveSideEffect(e))) { makeQueried(); break; } } } if (call.getArgumentList().getExpressionCount() == 2 && ("poll".equals(name) || "pollFirst".equals(name) || "pollLast".equals(name)) && TypeUtils.variableHasTypeOrSubtype(myVariable, "java.util.concurrent.BlockingQueue")) { // poll(timeout, unit) on a blocking queue/dequeue may be considered querying, even if the result is not used, // because the thread will be blocked until a value is received (or a timeout happens). makeQueried(); } else if (("take".equals(name) || "takeFirst".equals(name) || "takeLast".equals(name)) && TypeUtils.variableHasTypeOrSubtype(myVariable, "java.util.concurrent.BlockingQueue")) { // take() on a blocking queue/dequeue may be considered querying, even if the result is not used. // because the thread will be blocked until a value is received. makeQueried(); } } } if (!queryQualifier && !updateQualifier) { if (!isQueryMethod(call)) { makeUpdated(); } makeQueried(); } }