void (@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) { PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class); if (!isCollectorMethod(call, "groupingBy", "groupingByConcurrent")) return; PsiExpression[] args = call.getArgumentList().getExpressions(); if (args.length != 2 && args.length != 3) return; CombinedCollector combinedCollector = new CombinedCollector(ArrayUtil.getLastElement(args), null, null); // Unwrap at most twice to gather collectingAndThen and/or mapping combinedCollector = combinedCollector.tryUnwrap().tryUnwrap(); PsiMethodCallExpression downstream = ObjectUtils.tryCast(combinedCollector.myDownstream, PsiMethodCallExpression.class); if (downstream == null || !FunctionalExpressionUtils.isFunctionalReferenceTo(combinedCollector.myFinisher, CommonClassNames.JAVA_UTIL_OPTIONAL, null, "get")) { return; } PsiExpression[] downstreamArgs = downstream.getArgumentList().getExpressions(); if (downstreamArgs.length != 1) return; PsiExpression downstreamArg = downstreamArgs[0]; String downstreamName = downstream.getMethodExpression().getReferenceName(); if (downstreamName == null) return; CommentTracker ct = new CommentTracker(); PsiType collectorType = call.getType(); PsiType mapType = PsiUtil.substituteTypeParameter(collectorType, "java.util.stream.Collector", 2, false); PsiType valueType = PsiUtil.substituteTypeParameter(mapType, CommonClassNames.JAVA_UTIL_MAP, 1, false); String valueTypeArg = valueType == null ? "" : "<" + valueType.getCanonicalText() + ">"; String merger; switch (downstreamName) { case "minBy", "maxBy" -> merger = "java.util.function.BinaryOperator." + valueTypeArg + downstreamName + "(" + ct.text(downstreamArg) + ")"; case "reducing" -> merger = ct.text(downstreamArg); default -> { return; } } String keyMapper = ct.text(args[0]); String mapSupplier = args.length == 3 ? ct.text(args[1]) : null; String valueMapper = combinedCollector.myMapper == null ? CommonClassNames.JAVA_UTIL_FUNCTION_FUNCTION + "." + valueTypeArg + "identity()" : ct.text(combinedCollector.myMapper); String replacement = StreamEx.of(keyMapper, valueMapper, merger, mapSupplier).nonNull() .joining(",", CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS + "." + myMethodName + "(", ")"); PsiElement result = ct.replaceAndRestoreComments(call, replacement); RemoveRedundantTypeArgumentsUtil.removeRedundantTypeArguments(result); result = JavaCodeStyleManager.getInstance(project).shortenClassReferences(result); CodeStyleManager.getInstance(project).reformat(result); }