TypeConversionDescriptorBase (@NotNull @NlsSafe String methodName, @NotNull PsiMethod method, @NotNull PsiType from, @Nullable PsiExpression context) { TypeConversionDescriptor descriptorBase = null; PsiType conversionType = null; boolean needSpecifyType = true; switch (methodName) { case "of" -> descriptorBase = new TypeConversionDescriptor("'_FluentIterable?.of($arr$)", "java.util.Arrays.stream($arr$)"); case "from" -> descriptorBase = new TypeConversionDescriptor("'_FluentIterable?.from($it$)", null) { @Override public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) { final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expression; PsiExpression argument = PseudoLambdaReplaceTemplate.replaceTypeParameters(methodCall.getArgumentList().getExpressions()[0]); if (argument == null) { return expression; } boolean isCollection = InheritanceUtil.isInheritor(PsiTypesUtil.getPsiClass(argument.getType()), CommonClassNames.JAVA_UTIL_COLLECTION); setReplaceByString(isCollection ? "($it$).stream()" : "java.util.stream.StreamSupport.stream(($it$).spliterator(), false)"); final PsiExpression replaced = super.replace(expression, evaluator); ParenthesesUtils.removeParentheses(replaced, false); return replaced; } }; case "filter" -> descriptorBase = FluentIterableConversionUtil.getFilterDescriptor(method, context); case "isEmpty" -> { descriptorBase = new TypeConversionDescriptor("$q$.isEmpty()", null) { @Override public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) { final PsiElement parent = expression.getParent(); boolean isDoubleNegation = false; if (parent instanceof PsiExpression && DoubleNegationInspection.isNegation((PsiExpression)parent)) { isDoubleNegation = true; expression = (PsiExpression)parent.replace(expression); } setReplaceByString((isDoubleNegation ? "" : "!") + "$q$.findAny().isPresent()"); return super.replace(expression, evaluator); } }; needSpecifyType = false; } case "transformAndConcat" -> descriptorBase = new FluentIterableConversionUtil.TransformAndConcatConversionRule(context); case "toArray" -> { descriptorBase = FluentIterableConversionUtil.getToArrayDescriptor(from, context); needSpecifyType = false; } case "copyInto" -> { descriptorBase = new FluentIterableConversionUtil.CopyIntoConversionDescriptor(); needSpecifyType = false; } case "append" -> descriptorBase = createDescriptorForAppend(method, context); case "get" -> { descriptorBase = new TypeConversionDescriptor("$it$.get($p$)", null) { @Override public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) { PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expression; final PsiExpression[] arguments = methodCall.getArgumentList().getExpressions(); setReplaceByString("$it$.skip($p$).findFirst().get()"); if (arguments.length == 1 && arguments[0] instanceof PsiLiteralExpression) { final Object value = ((PsiLiteralExpression)arguments[0]).getValue(); if (value != null && value.equals(0)) { setReplaceByString("$it$.findFirst().get()"); } } return super.replace(expression, evaluator); } }; needSpecifyType = false; } case "contains" -> { descriptorBase = new TypeConversionDescriptor("$it$.contains($o$)", null) { @Override public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) { final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; final PsiExpression qualifier = methodCallExpression.getMethodExpression().getQualifierExpression(); LOG.assertTrue(qualifier != null); final PsiClassType qualifierType = (PsiClassType)qualifier.getType(); LOG.assertTrue(qualifierType != null); final PsiType[] parameters = qualifierType.getParameters(); final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject()); final SuggestedNameInfo suggestedNameInfo = codeStyleManager .suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, parameters.length == 1 ? parameters[0] : null, false); final String suggestedName = codeStyleManager.suggestUniqueVariableName(suggestedNameInfo, expression, false).names[0]; setReplaceByString("$it$.anyMatch(" + suggestedName + " -> java.util.Objects.equals(" + suggestedName + ", $o$))"); return super.replace(expression, evaluator); } }; needSpecifyType = false; } case "last" -> descriptorBase = new TypeConversionDescriptor("$it$.last()", null) { @Override public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) { final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject()); String varA = suggestName("a", codeStyleManager, expression); String varB = suggestName("b", codeStyleManager, expression); setReplaceByString("$it$.reduce((" + varA + ", " + varB + ") -> " + varB + ")"); return super.replace(expression, evaluator); } private static String suggestName(String baseName, JavaCodeStyleManager codeStyleManager, PsiElement place) { final SuggestedNameInfo suggestedNameInfo = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, baseName, null, null, false); return codeStyleManager.suggestUniqueVariableName(suggestedNameInfo, place, false).names[0]; } }; default -> { final TypeConversionDescriptorFactory base = DESCRIPTORS_MAP.get(methodName); if (base != null) { final TypeConversionDescriptor descriptor = base.create(context); needSpecifyType = base.isChainedMethod(); if (needSpecifyType && !base.isFluentIterableReturnType()) { conversionType = GuavaConversionUtil.addTypeParameters(GuavaOptionalConversionRule.JAVA_OPTIONAL, context.getType(), context); } descriptorBase = descriptor; } } } if (descriptorBase == null) { return FluentIterableConversionUtil.createToCollectionDescriptor(methodName, context); } if (needSpecifyType) { if (conversionType == null) { PsiMethodCallExpression methodCall = (PsiMethodCallExpression) (context instanceof PsiMethodCallExpression ? context : context.getParent()); conversionType = GuavaConversionUtil.addTypeParameters(GuavaTypeConversionDescriptor.isIterable(methodCall) ? CommonClassNames.JAVA_LANG_ITERABLE : StreamApiConstants.JAVA_UTIL_STREAM_STREAM, context.getType(), context); } descriptorBase.withConversionType(conversionType); } return descriptorBase; }