@Override
    protected void applyFix(@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);
    }
@Override
    protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater)