List<OperationRecord> (PsiMethodCallExpression terminalCall) { if (!ITERABLE_FOREACH.test(terminalCall) || !ExpressionUtils.isVoidContext(terminalCall)) return null; PsiExpression qualifier = ExpressionUtils.getEffectiveQualifier(terminalCall.getMethodExpression()); if (qualifier == null) return null; // Do not visit this path if some class implements both Iterable and Stream PsiType type = qualifier.getType(); if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM)) return null; PsiExpression arg = terminalCall.getArgumentList().getExpressions()[0]; FunctionHelper fn = FunctionHelper.create(arg, 1, true); if (fn == null) return null; PsiType elementType = PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_LANG_ITERABLE, 0, false); if (!isValidElementType(elementType, terminalCall, true)) return null; elementType = GenericsUtil.getVariableTypeByExpressionType(elementType); TerminalOperation terminal = new TerminalOperation.ForEachTerminalOperation(fn); SourceOperation source = new SourceOperation.ForEachSource(qualifier); OperationRecord terminalRecord = new OperationRecord(); OperationRecord sourceRecord = new OperationRecord(); terminalRecord.myOperation = terminal; sourceRecord.myOperation = source; sourceRecord.myOutVar = terminalRecord.myInVar = new ChainVariable(elementType); sourceRecord.myInVar = terminalRecord.myOutVar = ChainVariable.STUB; return Arrays.asList(sourceRecord, terminalRecord); }