List<OperationRecord> (PsiMethodCallExpression terminalCall) { if (!MAP_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 Map 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, 2, true); if (fn == null) return null; PsiType keyType = PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 0, false); PsiType valueType = PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_MAP, 1, false); if (!isValidElementType(keyType, terminalCall, true) || !isValidElementType(valueType, terminalCall, true)) return null; Project project = terminalCall.getProject(); JavaPsiFacade facade = JavaPsiFacade.getInstance(project); PsiClass entryClass = facade.findClass(CommonClassNames.JAVA_UTIL_MAP_ENTRY, terminalCall.getResolveScope()); if (entryClass == null || entryClass.getTypeParameters().length != 2) return null; PsiType entryType = JavaPsiFacade.getElementFactory(project).createType(entryClass, keyType, valueType); keyType = GenericsUtil.getVariableTypeByExpressionType(keyType); valueType = GenericsUtil.getVariableTypeByExpressionType(valueType); TerminalOperation terminal = new TerminalOperation.MapForEachTerminalOperation(fn, keyType, valueType); SourceOperation source = new SourceOperation.ForEachSource(qualifier, true); OperationRecord terminalRecord = new OperationRecord(); OperationRecord sourceRecord = new OperationRecord(); terminalRecord.myOperation = terminal; sourceRecord.myOperation = source; sourceRecord.myOutVar = terminalRecord.myInVar = new ChainVariable(entryType); sourceRecord.myInVar = terminalRecord.myOutVar = ChainVariable.STUB; return Arrays.asList(sourceRecord, terminalRecord); }