FunctionHelper (PsiExpression expression, int paramCount, boolean allowReturns) { expression = PsiUtil.skipParenthesizedExprDown(expression); if(expression == null) return null; PsiType type = FunctionalExpressionUtils.getFunctionalExpressionType(expression); if(!(type instanceof PsiClassType)) return null; PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(type); if (interfaceMethod == null || interfaceMethod.getParameterList().getParametersCount() != paramCount) return null; PsiType returnType = interfaceMethod.getReturnType(); if (returnType == null) return null; returnType = ((PsiClassType)type).resolveGenerics().getSubstitutor().substitute(returnType); if (expression instanceof PsiLambdaExpression lambda) { PsiParameterList list = lambda.getParameterList(); if (list.getParametersCount() != paramCount) return null; String[] parameters = StreamEx.of(list.getParameters()).map(PsiVariable::getName).toArray(String[]::new); PsiElement body = lambda.getBody(); PsiExpression lambdaExpression = LambdaUtil.extractSingleExpressionFromBody(body); if (lambdaExpression == null) { if (body instanceof PsiCodeBlock block) { List<PsiReturnStatement> returns = getReturns(body); if (PsiTypes.voidType().equals(returnType)) { if (!allowReturns && (!returns.isEmpty() || !ControlFlowUtils.codeBlockMayCompleteNormally(block))) return null; // Return inside loop is not supported yet for (PsiReturnStatement ret : returns) { if (PsiTreeUtil.getParentOfType(ret, PsiLoopStatement.class, true, PsiLambdaExpression.class) != null) { return null; } } return new VoidBlockLambdaFunctionHelper(block, parameters); } else if (returns.size() == 1 && ArrayUtil.getLastElement(block.getStatements()) == returns.get(0)) { PsiExpression trivialCall = JavaPsiFacade.getElementFactory(lambda.getProject()) .createExpressionFromText("((" + type.getCanonicalText() + ")" + lambda.getText() + ")." + interfaceMethod.getName() + "(" + String.join(",", parameters) + ")", lambda); return new LambdaFunctionHelper(returnType, trivialCall, parameters); } } return null; } return new LambdaFunctionHelper(returnType, lambdaExpression, parameters); } if (expression instanceof PsiMethodReferenceExpression methodRef) { if (methodRef.resolve() == null) return null; String template = tryInlineMethodReference(paramCount, methodRef); if (template != null) { return new InlinedFunctionHelper(returnType, paramCount, template); } return new MethodReferenceFunctionHelper(returnType, type, methodRef); } if (expression instanceof PsiReferenceExpression && ExpressionUtils.isSafelyRecomputableExpression(expression)) { return new SimpleReferenceFunctionHelper(returnType, expression, interfaceMethod.getName()); } if (expression instanceof PsiMethodCallExpression call) { if (MethodCallUtils.isCallToStaticMethod(call, CommonClassNames.JAVA_UTIL_FUNCTION_FUNCTION, "identity", 0)) { return paramCount == 1 ? new InlinedFunctionHelper(returnType, 1, "{0}") : null; } if (MethodCallUtils.isCallToStaticMethod(call, CommonClassNames.JAVA_UTIL_COMPARATOR, "naturalOrder", 0)) { return paramCount == 2 ? new InlinedFunctionHelper(returnType, 2, "{0}.compareTo({1})") : null; } if (MethodCallUtils.isCallToStaticMethod(call, CommonClassNames.JAVA_UTIL_COMPARATOR, "reverseOrder", 0) || MethodCallUtils.isCallToStaticMethod(call, CommonClassNames.JAVA_UTIL_COLLECTIONS, "reverseOrder", 0)) { return paramCount == 2 ? new InlinedFunctionHelper(returnType, 2, "{1}.compareTo({0})") : null; } } return new ComplexExpressionFunctionHelper(returnType, type, interfaceMethod.getName(), expression); }