void (@NotNull PsiMethodCallExpression call) { if (STREAM_OF_SINGLE.test(call)) { handleSingleElementStream(call); } PsiReferenceExpression methodExpression = call.getMethodExpression(); String name = methodExpression.getReferenceName(); if (name == null || !INTERESTING_NAMES.contains(name)) return; PsiExpression qualifier = call.getMethodExpression().getQualifierExpression(); if (qualifier == null) return; PsiMethod method = call.resolveMethod(); if (method == null) return; PsiClass aClass = method.getContainingClass(); if (aClass == null) return; String className = aClass.getQualifiedName(); if (className == null) return; boolean optional = OptionalUtil.isJdkOptionalClassName(className); boolean stream = InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM); if (!optional && !stream) return; PsiExpression[] args = call.getArgumentList().getExpressions(); if (name.equals("flatMap") && args.length == 1 && isIdentityMapping(args[0], false)) { PsiMethodCallExpression qualifierCall = MethodCallUtils.getQualifierMethodCall(call); if (STREAM_MAP.test(qualifierCall) && qualifierCall.getMethodExpression().getTypeParameters().length == 0 && !isIdentityMapping(qualifierCall.getArgumentList().getExpressions()[0], false)) { String message = JavaBundle.message("inspection.redundant.stream.optional.call.message", name) + ": " + JavaBundle.message("inspection.redundant.stream.optional.call.explanation.map.flatMap"); holder.registerProblem(call, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, getRange(call), new RemoveCallFix(name, "map")); } } if (!EquivalenceChecker.getCanonicalPsiEquivalence().typesAreEquivalent(qualifier.getType(), call.getType())) return; switch (name) { case "filter" -> { if (args.length == 1 && isTruePredicate(args[0])) { register(call, JavaBundle.message("inspection.redundant.stream.optional.call.explanation.filter")); } } case "map" -> { boolean allowBoxUnbox = USELESS_BOXING_IN_STREAM_MAP || optional || StreamApiUtil.getStreamElementType(call.getType()) instanceof PsiPrimitiveType; if (args.length == 1 && isIdentityMapping(args[0], allowBoxUnbox)) { register(call, null); } } case "flatMap" -> { if (args.length == 1) { if (optional) { if (FunctionalExpressionUtils .isFunctionalReferenceTo(args[0], CommonClassNames.JAVA_UTIL_OPTIONAL, null, "of", new PsiType[1]) || FunctionalExpressionUtils .isFunctionalReferenceTo(args[0], CommonClassNames.JAVA_UTIL_OPTIONAL, null, "ofNullable", new PsiType[1])) { register(call, null); } } else { if (FunctionalExpressionUtils .isFunctionalReferenceTo(args[0], CommonClassNames.JAVA_UTIL_STREAM_STREAM, null, "of", new PsiType[1])) { register(call, null); } } } } case "sorted" -> { if (args.length <= 1) { PsiMethodCallExpression furtherCall = findCallThatSpoilsSorting(call); if (furtherCall != null) { String furtherCallName = furtherCall.getMethodExpression().getReferenceName(); String terminalReplacement = CALLS_MAKING_SORT_USELESS_PARALLEL.get(furtherCallName); if (terminalReplacement != null && !isParallelStream(call)) return; if (("max".equals(furtherCallName) || "min".equals(furtherCallName)) && !sortingCancelsPreviousSorting(call, furtherCall)) { return; } LocalQuickFix additionalFix = null; if ("toSet".equals(furtherCallName) || "toCollection".equals(furtherCallName)) { additionalFix = new CollectToOrderedSetFix(); } else if (terminalReplacement != null) { additionalFix = new ReplaceTerminalCallFix(terminalReplacement); } String message = "sorted".equals(furtherCallName) ? JavaBundle.message("inspection.redundant.stream.optional.call.explanation.sorted.twice") : terminalReplacement != null ? JavaBundle.message("inspection.redundant.stream.optional.call.explanation.sorted.parallel", furtherCallName) : JavaBundle.message("inspection.redundant.stream.optional.call.explanation.sorted", furtherCallName); register(call, message, LocalQuickFix.notNullElements(additionalFix)); } } } case "distinct" -> { if (args.length == 0) { PsiMethodCallExpression furtherCall = findSubsequentCall(call, Predicate.isEqual("distinct"), CALLS_KEEPING_ELEMENTS_DISTINCT::contains); if (furtherCall != null && furtherCall.getArgumentList().isEmpty()) { register(furtherCall, JavaBundle.message("inspection.redundant.stream.optional.call.explanation.distinct")); } Predicate<PsiMethodCallExpression> setCollector = COLLECTOR_TO_SET.or(RedundantStreamOptionalCallInspection::isToCollectionSet); if (findSubsequentCall(call, c -> false, setCollector, Set.of("unordered", "parallel", "sequential", "sorted")::contains) != null) { register(call, JavaBundle.message("inspection.redundant.stream.optional.call.explanation.distinct.set")); } } } case "unordered" -> { if (args.length == 0) { PsiMethodCallExpression furtherCall = findSubsequentCall(call, Predicate.isEqual("unordered"), n -> !n.equals("sorted")); if (furtherCall != null && furtherCall.getArgumentList().isEmpty()) { register(furtherCall, JavaBundle.message("inspection.redundant.stream.optional.call.explanation.unordered")); } } } case "sequential", "parallel" -> { if (args.length == 0) { PsiMethodCallExpression furtherCall = findSubsequentCall(call, CALLS_AFFECTING_PARALLELIZATION::contains, n -> true); if (furtherCall != null && furtherCall.getArgumentList().isEmpty()) { register(call, JavaBundle.message("inspection.redundant.stream.optional.call.explanation.parallel", furtherCall.getMethodExpression().getReferenceName())); } else { PsiMethodCallExpression previousCall = MethodCallUtils.getQualifierMethodCall(call); while (true) { if (previousCall == null) break; String prevName = previousCall.getMethodExpression().getReferenceName(); if (prevName == null) break; if (CALLS_AFFECTING_PARALLELIZATION.contains(prevName)) break; // already reported on previous call if (COLLECTION_STREAM_SOURCE.test(previousCall)) { boolean previousParallel = prevName.equals("parallelStream"); boolean curParallel = name.equals("parallel"); if (previousParallel == curParallel) { register(call, JavaBundle.message(curParallel ? "inspection.redundant.stream.optional.call.explanation.parallel.source" : "inspection.redundant.stream.optional.call.explanation.sequential.source")); break; } } if (StreamApiUtil.getStreamElementType(previousCall.getType()) == null) break; previousCall = MethodCallUtils.getQualifierMethodCall(previousCall); } } } } } }