From 21564bba7b760a168664e6839dd68d556d9823f1 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Mon, 7 Nov 2016 17:20:46 +0700 Subject: [PATCH] IDEA-163627 Simplify optional.isPresent() inspection could better handle some specific cases IDEA-163462 Simplify Optional.isPresent() ? Optional.get() : ... --- .../OptionalIsPresentInspection.java | 274 ++++++++++-------- .../ReplaceWithFindFirstFix.java | 37 +-- .../StreamApiMigrationInspection.java | 13 +- .../streamToLoop/TerminalOperation.java | 47 +-- .../codeInspection/util/OptionalUtil.java | 159 ++++++++++ .../optionalIsPresent/afterAssignment.java | 2 +- .../afterAssignmentField.java | 2 +- .../optionalIsPresent/afterAssignmentMap.java | 2 +- .../afterAssignmentMapOrElseGet.java | 2 +- .../optionalIsPresent/afterConsumer.java | 2 +- .../optionalIsPresent/afterConsumerField.java | 2 +- .../optionalIsPresent/afterReturn.java | 2 +- .../optionalIsPresent/afterReturnCast.java | 16 + .../afterReturnComments.java | 2 +- .../optionalIsPresent/afterReturnList.java | 2 +- .../optionalIsPresent/afterReturnNot.java | 2 +- .../optionalIsPresent/afterReturnSimple.java | 2 +- .../optionalIsPresent/afterSelfAsEmpty.java | 12 + .../optionalIsPresent/afterTernary.java | 16 + .../afterTernaryFlatMap.java | 20 ++ .../afterTernaryNegatedMap.java | 16 + .../afterTernaryOptional.java | 16 + .../optionalIsPresent/beforeAssignment.java | 2 +- .../beforeAssignmentField.java | 2 +- .../beforeAssignmentMap.java | 2 +- .../beforeAssignmentMapOrElseGet.java | 2 +- .../optionalIsPresent/beforeConsumer.java | 2 +- .../beforeConsumerField.java | 2 +- .../beforeConsumerNoGet.java | 2 +- .../beforeConsumerTwoStatements.java | 2 +- .../optionalIsPresent/beforeReturn.java | 2 +- .../optionalIsPresent/beforeReturnCast.java | 19 ++ .../beforeReturnComments.java | 2 +- .../beforeReturnInterrupted.java | 2 +- .../optionalIsPresent/beforeReturnList.java | 2 +- .../beforeReturnNonFinalUsed.java | 2 +- .../optionalIsPresent/beforeReturnNot.java | 2 +- .../optionalIsPresent/beforeReturnRaw.java | 2 +- .../optionalIsPresent/beforeReturnSimple.java | 2 +- .../optionalIsPresent/beforeSelfAsEmpty.java | 16 + .../optionalIsPresent/beforeTernary.java | 16 + .../beforeTernaryFlatMap.java | 20 ++ .../beforeTernaryNegatedMap.java | 16 + .../beforeTernaryOptional.java | 16 + .../afterFindFirstOptional.java | 17 ++ .../afterFindFirstOptionalFlatMap.java | 15 + .../beforeFindFirstOptional.java | 23 ++ .../beforeFindFirstOptionalFlatMap.java | 21 ++ .../siyeh/ig/psiutils/ExpressionUtils.java | 5 + 49 files changed, 628 insertions(+), 236 deletions(-) rename java/{java-analysis-impl => java-impl}/src/com/intellij/codeInspection/OptionalIsPresentInspection.java (52%) create mode 100644 java/java-impl/src/com/intellij/codeInspection/util/OptionalUtil.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnCast.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterSelfAsEmpty.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernary.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryFlatMap.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryNegatedMap.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryOptional.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnCast.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeSelfAsEmpty.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernary.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryFlatMap.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryNegatedMap.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryOptional.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFindFirstOptional.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFindFirstOptionalFlatMap.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstOptional.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstOptionalFlatMap.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java similarity index 52% rename from java/java-analysis-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java rename to java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java index 93f360530609..dbb036e1ce65 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInspection.util.LambdaGenerationUtil; +import com.intellij.codeInspection.util.OptionalUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.*; @@ -47,7 +48,8 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo private static final OptionalIfPresentCase[] CASES = { new ReturnCase(), new AssignmentCase(), - new ConsumerCase() + new ConsumerCase(), + new TernaryCase() }; @NotNull @@ -58,25 +60,46 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo } return new JavaElementVisitor() { @Override - public void visitIfStatement(PsiIfStatement statement) { - super.visitIfStatement(statement); - PsiExpression condition = PsiUtil.skipParenthesizedExprDown(statement.getCondition()); - if(condition == null) return; + public void visitConditionalExpression(PsiConditionalExpression expression) { + super.visitConditionalExpression(expression); + PsiExpression condition = PsiUtil.skipParenthesizedExprDown(expression.getCondition()); + if (condition == null) return; boolean invert = false; PsiExpression strippedCondition = condition; - if(BoolUtils.isNegation(condition)) { + if (BoolUtils.isNegation(condition)) { strippedCondition = BoolUtils.getNegated(condition); invert = true; } PsiVariable optionalVariable = extractOptionalFromIfPresentCheck(strippedCondition); - if(optionalVariable == null) return; + if (optionalVariable == null) return; + PsiExpression thenExpression = invert ? expression.getElseExpression() : expression.getThenExpression(); + PsiExpression elseExpression = invert ? expression.getThenExpression() : expression.getElseExpression(); + check(condition, optionalVariable, thenExpression, elseExpression); + } + + @Override + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + PsiExpression condition = PsiUtil.skipParenthesizedExprDown(statement.getCondition()); + if (condition == null) return; + boolean invert = false; + PsiExpression strippedCondition = condition; + if (BoolUtils.isNegation(condition)) { + strippedCondition = BoolUtils.getNegated(condition); + invert = true; + } + PsiVariable optionalVariable = extractOptionalFromIfPresentCheck(strippedCondition); + if (optionalVariable == null) return; PsiStatement thenStatement = extractThenStatement(statement, invert); PsiStatement elseStatement = extractElseStatement(statement, invert); - for(OptionalIfPresentCase scenario : CASES) { - String replacementName = scenario.getReplacementName(optionalVariable, thenStatement, elseStatement); - if(replacementName != null) { - holder.registerProblem(condition, "Can be replaced with "+replacementName, - new OptionalIfPresentFix(scenario, replacementName)); + check(condition, optionalVariable, thenStatement, elseStatement); + } + + void check(PsiExpression condition, PsiVariable optionalVariable, PsiElement thenElement, PsiElement elseElement) { + for (OptionalIfPresentCase scenario : CASES) { + if (scenario.isApplicable(optionalVariable, thenElement, elseElement)) { + holder.registerProblem(condition, "Can be replaced with single expression in functional style", + new OptionalIfPresentFix(scenario)); } } } @@ -90,18 +113,18 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo @Nullable private static PsiStatement extractThenStatement(PsiIfStatement ifStatement, boolean invert) { - if(invert) return extractElseStatement(ifStatement, false); + if (invert) return extractElseStatement(ifStatement, false); return ControlFlowUtils.stripBraces(ifStatement.getThenBranch()); } private static PsiStatement extractElseStatement(PsiIfStatement ifStatement, boolean invert) { - if(invert) return extractThenStatement(ifStatement, false); + if (invert) return extractThenStatement(ifStatement, false); PsiStatement statement = ControlFlowUtils.stripBraces(ifStatement.getElseBranch()); - if(statement == null) { + if (statement == null) { PsiStatement thenStatement = extractThenStatement(ifStatement, false); - if(thenStatement instanceof PsiReturnStatement) { + if (thenStatement instanceof PsiReturnStatement) { PsiElement nextElement = PsiTreeUtil.skipSiblingsForward(ifStatement, PsiComment.class, PsiWhiteSpace.class); - if(nextElement instanceof PsiStatement) { + if (nextElement instanceof PsiStatement) { statement = ControlFlowUtils.stripBraces((PsiStatement)nextElement); } } @@ -111,16 +134,16 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo @Contract("null -> null") static PsiVariable extractOptionalFromIfPresentCheck(PsiExpression expression) { - if(!(expression instanceof PsiMethodCallExpression)) return null; + if (!(expression instanceof PsiMethodCallExpression)) return null; PsiMethodCallExpression call = (PsiMethodCallExpression)expression; - if(call.getArgumentList().getExpressions().length != 0) return null; - if(!"isPresent".equals(call.getMethodExpression().getReferenceName())) return null; + if (call.getArgumentList().getExpressions().length != 0) return null; + if (!"isPresent".equals(call.getMethodExpression().getReferenceName())) return null; PsiMethod method = call.resolveMethod(); - if(method == null) return null; + if (method == null) return null; PsiClass containingClass = method.getContainingClass(); if (containingClass == null || !CommonClassNames.JAVA_UTIL_OPTIONAL.equals(containingClass.getQualifiedName())) return null; PsiExpression qualifier = call.getMethodExpression().getQualifierExpression(); - if(!(qualifier instanceof PsiReferenceExpression)) return null; + if (!(qualifier instanceof PsiReferenceExpression)) return null; PsiElement element = ((PsiReferenceExpression)qualifier).resolve(); if (!(element instanceof PsiVariable) || isRaw((PsiVariable)element)) return null; return (PsiVariable)element; @@ -128,23 +151,23 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo @Contract("null, _ -> false") static boolean isOptionalGetCall(PsiElement element, PsiVariable variable) { - if(!(element instanceof PsiMethodCallExpression)) return false; + if (!(element instanceof PsiMethodCallExpression)) return false; PsiMethodCallExpression call = (PsiMethodCallExpression)element; - if(call.getArgumentList().getExpressions().length != 0) return false; - if(!"get".equals(call.getMethodExpression().getReferenceName())) return false; + if (call.getArgumentList().getExpressions().length != 0) return false; + if (!"get".equals(call.getMethodExpression().getReferenceName())) return false; PsiExpression qualifier = call.getMethodExpression().getQualifierExpression(); - if(!(qualifier instanceof PsiReferenceExpression)) return false; + if (!(qualifier instanceof PsiReferenceExpression)) return false; return ((PsiReferenceExpression)qualifier).isReferenceTo(variable); } @Contract("null, _ -> false") static boolean isOptionalLambdaCandidate(PsiExpression lambdaCandidate, PsiVariable optionalVariable) { - if(lambdaCandidate == null) return false; - if(!ExceptionUtil.getThrownCheckedExceptions(lambdaCandidate).isEmpty()) return false; + if (lambdaCandidate == null) return false; + if (!ExceptionUtil.getThrownCheckedExceptions(lambdaCandidate).isEmpty()) return false; return PsiTreeUtil.processElements(lambdaCandidate, e -> { if (!(e instanceof PsiReferenceExpression)) return true; PsiElement element = ((PsiReferenceExpression)e).resolve(); - if(!(element instanceof PsiVariable)) return true; + if (!(element instanceof PsiVariable)) return true; // Check that Optional variable is referenced only in context of get() call and other variables are effectively final return element == optionalVariable ? isOptionalGetCall(e.getParent().getParent(), optionalVariable) @@ -152,48 +175,41 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo }); } - @NotNull - static String generateMapIfNeeded(PsiElementFactory factory, - PsiVariable optionalVariable, - PsiExpression trueValue) { - String name = optionalVariable.getName(); - LOG.assertTrue(name != null); - if(isOptionalGetCall(trueValue, optionalVariable)) { - return name; - } else { - return name + ".map(" + generateOptionalLambda(factory, optionalVariable, trueValue) + ")"; - } - } - @NotNull static String generateOptionalLambda(PsiElementFactory factory, PsiVariable optionalVariable, PsiExpression trueValue) { PsiType type = optionalVariable.getType(); JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(trueValue.getProject()); SuggestedNameInfo info = javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type); - if(info.names.length == 0) + if (info.names.length == 0) { info = javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, "value", null, type); + } String paramName = javaCodeStyleManager.suggestUniqueVariableName(info, trueValue, true).names[0]; PsiElement copy = trueValue.copy(); for (PsiElement getCall : PsiTreeUtil.collectElements(copy, e -> isOptionalGetCall(e, optionalVariable))) { - getCall.replace(factory.createIdentifier(paramName)); + PsiElement result = getCall.replace(factory.createIdentifier(paramName)); + if (copy == getCall) copy = result; } return paramName + "->" + copy.getText(); } + static String generateOptionalUnwrap(PsiElementFactory factory, + PsiVariable optionalVariable, + PsiExpression trueValue, + PsiExpression falseValue) { + String lambdaText = generateOptionalLambda(factory, optionalVariable, trueValue); + PsiLambdaExpression lambda = (PsiLambdaExpression)factory.createExpressionFromText(lambdaText, trueValue); + if(falseValue instanceof PsiReferenceExpression && ((PsiReferenceExpression)falseValue).isReferenceTo(optionalVariable)) { + falseValue = factory.createExpressionFromText(CommonClassNames.JAVA_UTIL_OPTIONAL+".empty()", falseValue); + } + return OptionalUtil.generateOptionalUnwrap(optionalVariable.getName(), lambda.getParameterList().getParameters()[0], + (PsiExpression)lambda.getBody(), falseValue, falseValue.getType(), true); + } + static class OptionalIfPresentFix implements LocalQuickFix { private final OptionalIfPresentCase myScenario; - private final String myReplacementName; - public OptionalIfPresentFix(OptionalIfPresentCase scenario, String replacementName) { + public OptionalIfPresentFix(OptionalIfPresentCase scenario) { myScenario = scenario; - myReplacementName = replacementName; - } - - @Nls - @NotNull - @Override - public String getName() { - return "Replace Optional.isPresent() condition with "+myReplacementName; } @Nls @@ -206,141 +222,149 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { PsiElement element = descriptor.getStartElement(); - if(!(element instanceof PsiExpression)) return; - PsiIfStatement statement = PsiTreeUtil.getParentOfType(element, PsiIfStatement.class); - if(statement == null) return; + if (!(element instanceof PsiExpression)) return; PsiExpression condition = (PsiExpression)element; boolean invert = false; - if(BoolUtils.isNegation(condition)) { + if (BoolUtils.isNegation(condition)) { condition = BoolUtils.getNegated(condition); invert = true; } PsiVariable optionalVariable = extractOptionalFromIfPresentCheck(condition); - if(optionalVariable == null) return; - PsiStatement thenStatement = extractThenStatement(statement, invert); - PsiStatement elseStatement = extractElseStatement(statement, invert); - if (!myScenario.isApplicable(optionalVariable, thenStatement, elseStatement)) return; + if (optionalVariable == null) return; + PsiElement cond = PsiTreeUtil.getParentOfType(element, PsiIfStatement.class, PsiConditionalExpression.class); + PsiElement thenElement; + PsiElement elseElement; + if(cond instanceof PsiIfStatement) { + thenElement = extractThenStatement((PsiIfStatement)cond, invert); + elseElement = extractElseStatement((PsiIfStatement)cond, invert); + } else if(cond instanceof PsiConditionalExpression) { + thenElement = invert ? ((PsiConditionalExpression)cond).getElseExpression() : ((PsiConditionalExpression)cond).getThenExpression(); + elseElement = invert ? ((PsiConditionalExpression)cond).getThenExpression() : ((PsiConditionalExpression)cond).getElseExpression(); + } else return; + if (!myScenario.isApplicable(optionalVariable, thenElement, elseElement)) return; if (!FileModificationService.getInstance().preparePsiElementForWrite(element.getContainingFile())) return; PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - PsiElement parent = statement.getParent(); - StreamEx.of(statement, thenStatement, elseStatement).nonNull() + PsiElement parent = cond.getParent(); + StreamEx.of(cond, thenElement, elseElement).nonNull() .flatCollection(st -> PsiTreeUtil.findChildrenOfType(st, PsiComment.class)) .distinct() .forEach(comment -> { - parent.addBefore(comment, statement); + parent.addBefore(comment, cond); comment.delete(); }); - String replacement = myScenario.generateReplacement(factory, optionalVariable, thenStatement, elseStatement); - if(thenStatement != null && !PsiTreeUtil.isAncestor(statement, thenStatement, true)) thenStatement.delete(); - if(elseStatement != null && !PsiTreeUtil.isAncestor(statement, elseStatement, true)) elseStatement.delete(); - PsiElement result = statement.replace(factory.createStatementFromText(replacement, statement)); + String replacementText = myScenario.generateReplacement(factory, optionalVariable, thenElement, elseElement); + if (thenElement != null && !PsiTreeUtil.isAncestor(cond, thenElement, true)) thenElement.delete(); + if (elseElement != null && !PsiTreeUtil.isAncestor(cond, elseElement, true)) elseElement.delete(); + PsiElement replacement = cond instanceof PsiExpression ? + factory.createExpressionFromText(replacementText, cond) : + factory.createStatementFromText(replacementText, cond); + PsiElement result = cond.replace(replacement); LambdaCanBeMethodReferenceInspection.replaceAllLambdasWithMethodReferences(result); CodeStyleManager.getInstance(project).reformat(result); } } interface OptionalIfPresentCase { - String getReplacementName(PsiVariable optionalVariable, PsiStatement trueStatement, PsiStatement falseStatement); - - default boolean isApplicable(PsiVariable optionalVariable, PsiStatement trueStatement, PsiStatement falseStatement) { - return getReplacementName(optionalVariable, trueStatement, falseStatement) != null; - } + boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement); String generateReplacement(PsiElementFactory factory, PsiVariable optionalVariable, - PsiStatement trueStatement, - PsiStatement falseStatement); + PsiElement trueElement, + PsiElement falseElement); } static class ReturnCase implements OptionalIfPresentCase { @Override - public String getReplacementName(PsiVariable optionalVariable, PsiStatement trueStatement, PsiStatement falseStatement) { - if (!(trueStatement instanceof PsiReturnStatement) || !(falseStatement instanceof PsiReturnStatement)) return null; - PsiExpression falseValue = ((PsiReturnStatement)falseStatement).getReturnValue(); - if(!ExpressionUtils.isSimpleExpression(falseValue)) return null; - PsiExpression trueValue = ((PsiReturnStatement)trueStatement).getReturnValue(); - if(!isOptionalLambdaCandidate(trueValue, optionalVariable)) return null; - return isOptionalGetCall(trueValue, optionalVariable) ? "orElse()" : "map().orElse()"; + public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if (!(trueElement instanceof PsiReturnStatement) || !(falseElement instanceof PsiReturnStatement)) return false; + PsiExpression falseValue = ((PsiReturnStatement)falseElement).getReturnValue(); + if (!ExpressionUtils.isSimpleExpression(falseValue) && + !LambdaGenerationUtil.canBeUncheckedLambda(falseValue)) return false; + PsiExpression trueValue = ((PsiReturnStatement)trueElement).getReturnValue(); + return isOptionalLambdaCandidate(trueValue, optionalVariable); } @Override public String generateReplacement(PsiElementFactory factory, PsiVariable optionalVariable, - PsiStatement trueStatement, - PsiStatement falseStatement) { - PsiExpression trueValue = ((PsiReturnStatement)trueStatement).getReturnValue(); - PsiExpression falseValue = ((PsiReturnStatement)falseStatement).getReturnValue(); + PsiElement trueElement, + PsiElement falseElement) { + PsiExpression trueValue = ((PsiReturnStatement)trueElement).getReturnValue(); + PsiExpression falseValue = ((PsiReturnStatement)falseElement).getReturnValue(); LOG.assertTrue(trueValue != null); LOG.assertTrue(falseValue != null); - String trueBranch = generateMapIfNeeded(factory, optionalVariable, trueValue); - return "return " + trueBranch + ".orElse(" + falseValue.getText() + ");"; + return "return " + generateOptionalUnwrap(factory, optionalVariable, trueValue, falseValue) + ";"; } } static class AssignmentCase implements OptionalIfPresentCase { - @Override - public String getReplacementName(PsiVariable optionalVariable, PsiStatement trueStatement, PsiStatement falseStatement) { - PsiAssignmentExpression trueAssignment = ExpressionUtils.getAssignment(trueStatement); - PsiAssignmentExpression falseAssignment = ExpressionUtils.getAssignment(falseStatement); + public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + PsiAssignmentExpression trueAssignment = ExpressionUtils.getAssignment(trueElement); + PsiAssignmentExpression falseAssignment = ExpressionUtils.getAssignment(falseElement); if (trueAssignment == null || falseAssignment == null || !EquivalenceChecker.getCanonicalPsiEquivalence() .expressionsAreEquivalent(trueAssignment.getLExpression(), falseAssignment.getLExpression()) || !isOptionalLambdaCandidate(trueAssignment.getRExpression(), optionalVariable)) { - return null; + return false; } - String mapPart = isOptionalGetCall(trueAssignment.getRExpression(), optionalVariable) ? "" : "map()."; - if(ExpressionUtils.isSimpleExpression(falseAssignment.getRExpression())) { - return mapPart + "orElse()"; - } - if(LambdaGenerationUtil.canBeUncheckedLambda(falseAssignment.getRExpression())) { - return mapPart + "orElseGet()"; - } - return null; + return ExpressionUtils.isSimpleExpression(falseAssignment.getRExpression()) || + LambdaGenerationUtil.canBeUncheckedLambda(falseAssignment.getRExpression()); } @Override public String generateReplacement(PsiElementFactory factory, PsiVariable optionalVariable, - PsiStatement trueStatement, - PsiStatement falseStatement) { - PsiAssignmentExpression trueAssignment = ExpressionUtils.getAssignment(trueStatement); - PsiAssignmentExpression falseAssignment = ExpressionUtils.getAssignment(falseStatement); + PsiElement trueElement, + PsiElement falseElement) { + PsiAssignmentExpression trueAssignment = ExpressionUtils.getAssignment(trueElement); + PsiAssignmentExpression falseAssignment = ExpressionUtils.getAssignment(falseElement); LOG.assertTrue(trueAssignment != null); LOG.assertTrue(falseAssignment != null); PsiExpression lValue = trueAssignment.getLExpression(); PsiExpression trueValue = trueAssignment.getRExpression(); PsiExpression falseValue = falseAssignment.getRExpression(); LOG.assertTrue(falseValue != null); - String trueBranch = generateMapIfNeeded(factory, optionalVariable, trueValue); - String falseBranch; - if(ExpressionUtils.isSimpleExpression(falseValue)) { - falseBranch = "orElse(" + falseValue.getText() + ")"; - } else { - falseBranch = "orElseGet(" + "() -> " + falseValue.getText() + ")"; - } - return lValue.getText() + " = " + trueBranch + "." + falseBranch + ";"; + return lValue.getText() + " = " + generateOptionalUnwrap(factory, optionalVariable, trueValue, falseValue) + ";"; } } - static class ConsumerCase implements OptionalIfPresentCase { - + static class TernaryCase implements OptionalIfPresentCase { @Override - public String getReplacementName(PsiVariable optionalVariable, PsiStatement trueStatement, PsiStatement falseStatement) { - if(falseStatement != null && !(falseStatement instanceof PsiEmptyStatement)) return null; - if(!(trueStatement instanceof PsiExpressionStatement)) return null; - PsiExpression expression = ((PsiExpressionStatement)trueStatement).getExpression(); - if(!isOptionalLambdaCandidate(expression, optionalVariable)) return null; - return "ifPresent()"; + public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if(!(trueElement instanceof PsiExpression) || !(falseElement instanceof PsiExpression)) return false; + return isOptionalLambdaCandidate((PsiExpression)trueElement, optionalVariable) && + (ExpressionUtils.isSimpleExpression((PsiExpression)falseElement) || + LambdaGenerationUtil.canBeUncheckedLambda((PsiExpression)falseElement)); } @Override public String generateReplacement(PsiElementFactory factory, PsiVariable optionalVariable, - PsiStatement trueStatement, - PsiStatement falseStatement) { - PsiExpression expression = ((PsiExpressionStatement)trueStatement).getExpression(); + PsiElement trueElement, + PsiElement falseElement) { + PsiExpression trueExpression = (PsiExpression)trueElement; + PsiExpression falseExpression = (PsiExpression)falseElement; + return generateOptionalUnwrap(factory, optionalVariable, trueExpression, falseExpression); + } + } + + static class ConsumerCase implements OptionalIfPresentCase { + @Override + public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if (falseElement != null && !(falseElement instanceof PsiEmptyStatement)) return false; + if (!(trueElement instanceof PsiExpressionStatement)) return false; + PsiExpression expression = ((PsiExpressionStatement)trueElement).getExpression(); + return isOptionalLambdaCandidate(expression, optionalVariable); + } + + @Override + public String generateReplacement(PsiElementFactory factory, + PsiVariable optionalVariable, + PsiElement trueElement, + PsiElement falseElement) { + PsiExpression expression = ((PsiExpressionStatement)trueElement).getExpression(); return optionalVariable.getName() + ".ifPresent(" + generateOptionalLambda(factory, optionalVariable, expression) + ");"; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithFindFirstFix.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithFindFirstFix.java index cca1d5ce74ee..f1213a5bef9a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithFindFirstFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithFindFirstFix.java @@ -15,12 +15,11 @@ */ package com.intellij.codeInspection.streamMigration; -import com.intellij.codeInsight.PsiEquivalenceUtil; import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus; +import com.intellij.codeInspection.util.OptionalUtil; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.util.RefactoringUtil; import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.NotNull; @@ -103,35 +102,9 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix { } } - private static String generateOptionalUnwrap(String stream, @NotNull StreamApiMigrationInspection.TerminalBlock tb, - PsiExpression trueExpression, PsiExpression falseExpression, PsiType targetType) { - PsiVariable var = tb.getVariable(); - if (!StreamApiMigrationInspection.isIdentityMapping(var, trueExpression)) { - if(trueExpression instanceof PsiTypeCastExpression && ExpressionUtils.isNullLiteral(falseExpression)) { - PsiTypeCastExpression castExpression = (PsiTypeCastExpression)trueExpression; - PsiTypeElement castType = castExpression.getCastType(); - // pull cast outside to avoid the .map() step - if(castType != null && StreamApiMigrationInspection.isIdentityMapping(var, castExpression.getOperand())) { - return "(" + castType.getText() + ")" + stream + ".orElse(null)"; - } - } - if(ExpressionUtils.isLiteral(falseExpression, Boolean.FALSE) && PsiType.BOOLEAN.equals(trueExpression.getType())) { - return stream + ".filter(" + LambdaUtil.createLambda(var, trueExpression) + ").isPresent()"; - } - if(trueExpression instanceof PsiConditionalExpression) { - PsiConditionalExpression condition = (PsiConditionalExpression)trueExpression; - PsiExpression elseExpression = condition.getElseExpression(); - if(elseExpression != null && PsiEquivalenceUtil.areElementsEquivalent(falseExpression, elseExpression)) { - return generateOptionalUnwrap( - stream + ".filter(" + LambdaUtil.createLambda(var, condition.getCondition()) + ")", tb, - condition.getThenExpression(), falseExpression, targetType); - } - } - trueExpression = - targetType == null ? trueExpression : RefactoringUtil.convertInitializerToNormalExpression(trueExpression, targetType); - stream += ".map(" + LambdaUtil.createLambda(var, trueExpression) + ")"; - } - stream += ".orElse(" + falseExpression.getText() + ")"; - return stream; + private static String generateOptionalUnwrap(String qualifier, StreamApiMigrationInspection.TerminalBlock tb, + PsiExpression trueExpression, PsiExpression falseExpression, + PsiType targetType) { + return OptionalUtil.generateOptionalUnwrap(qualifier, tb.getVariable(), trueExpression, falseExpression, targetType, false); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java index 2d969354f53d..32d594f56461 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java @@ -259,7 +259,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo final PsiVariable variable = tb.getVariable(); final PsiMethodCallExpression methodCallExpression = tb.getSingleMethodCall(); LOG.assertTrue(methodCallExpression != null); - if (!isIdentityMapping(variable, methodCallExpression.getArgumentList().getExpressions()[0])) return false; + if (!ExpressionUtils.isIdentityMapping(variable, methodCallExpression.getArgumentList().getExpressions()[0])) return false; PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); if(qualifierExpression == null || qualifierExpression instanceof PsiThisExpression) { PsiMethod method = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethod.class); @@ -384,11 +384,6 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo return ContainerUtil.find(method.getThrowsList().getReferencedTypes(), type -> !ExceptionUtil.isUncheckedException(type)) != null; } - @Contract("_, null -> false") - static boolean isIdentityMapping(PsiVariable variable, PsiExpression mapperCall) { - return mapperCall instanceof PsiReferenceExpression && ((PsiReferenceExpression)mapperCall).isReferenceTo(variable); - } - @Nullable private static PsiClassType createDefaultConsumerType(Project project, PsiVariable variable) { final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); @@ -671,7 +666,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo if(!(var instanceof PsiVariable) || !nonFinalVariables.contains(var)) return; PsiExpression rValue = assignment.getRExpression(); if(rValue == null || isVariableReferenced((PsiVariable)var, rValue)) return; - if(tb.getVariable().getType() instanceof PsiPrimitiveType && !isIdentityMapping(tb.getVariable(), rValue)) return; + if(tb.getVariable().getType() instanceof PsiPrimitiveType && !ExpressionUtils.isIdentityMapping(tb.getVariable(), rValue)) return; registerProblem(statement, "findFirst", new ReplaceWithFindFirstFix()); } } @@ -718,7 +713,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo registerProblem(statement, "anyMatch", new ReplaceWithMatchFix("anyMatch")); } if(nextReturnStatement != null && ExpressionUtils.isSimpleExpression(nextReturnStatement.getReturnValue()) - && (!(tb.getVariable().getType() instanceof PsiPrimitiveType) || isIdentityMapping(tb.getVariable(), value))) { + && (!(tb.getVariable().getType() instanceof PsiPrimitiveType) || ExpressionUtils.isIdentityMapping(tb.getVariable(), value))) { registerProblem(statement, "findFirst", new ReplaceWithFindFirstFix()); } } @@ -973,7 +968,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo @Override public String createReplacement() { - if (isIdentityMapping(myVariable, myExpression)) { + if (ExpressionUtils.isIdentityMapping(myVariable, myExpression)) { if (!(myType instanceof PsiPrimitiveType)) { return myVariable.getType() instanceof PsiPrimitiveType ? ".boxed()" : ""; } diff --git a/java/java-impl/src/com/intellij/codeInspection/streamToLoop/TerminalOperation.java b/java/java-impl/src/com/intellij/codeInspection/streamToLoop/TerminalOperation.java index aa14d1235213..1b590ace6ebc 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamToLoop/TerminalOperation.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamToLoop/TerminalOperation.java @@ -16,11 +16,11 @@ package com.intellij.codeInspection.streamToLoop; import com.intellij.codeInspection.streamToLoop.StreamToLoopInspection.StreamToLoopReplacementContext; +import com.intellij.codeInspection.util.OptionalUtil; import com.intellij.psi.*; import com.intellij.psi.util.TypeConversionUtil; import com.siyeh.ig.psiutils.BoolUtils; import one.util.streamex.StreamEx; -import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,21 +47,6 @@ abstract class TerminalOperation extends Operation { abstract String generate(StreamVariable inVar, StreamToLoopReplacementContext context); - @NotNull - @Contract(pure = true) - private static String getOptionalClass(String type) { - switch (type) { - case "int": - return "java.util.OptionalInt"; - case "long": - return "java.util.OptionalLong"; - case "double": - return "java.util.OptionalDouble"; - default: - return "java.util.Optional"; - } - } - @Nullable static TerminalOperation createTerminal(@NotNull String name, @NotNull PsiExpression[] args, @NotNull PsiType elementType, @NotNull PsiType resultType, boolean isVoid) { @@ -105,7 +90,7 @@ abstract class TerminalOperation extends Operation { } } if(args.length == 1) { - PsiType optionalElementType = getOptionalElementType(resultType); + PsiType optionalElementType = OptionalUtil.getOptionalElementType(resultType); FunctionHelper fn = FunctionHelper.create(args[0], 2); if(fn != null && optionalElementType != null) { return new ReduceToOptionalTerminalOperation(fn, optionalElementType.getCanonicalText()); @@ -169,7 +154,7 @@ abstract class TerminalOperation extends Operation { } } if(collector.getName().equals("reducing") && collectorArgs.length == 1) { - PsiType optionalElementType = getOptionalElementType(resultType); + PsiType optionalElementType = OptionalUtil.getOptionalElementType(resultType); FunctionHelper fn = FunctionHelper.create(collectorArgs[0], 2); if(fn != null && optionalElementType != null) { return new ReduceToOptionalTerminalOperation(fn, optionalElementType.getCanonicalText()); @@ -193,30 +178,6 @@ abstract class TerminalOperation extends Operation { return null; } - @Contract("null -> null") - static PsiType getOptionalElementType(PsiType type) { - if(!(type instanceof PsiClassType)) return null; - PsiClass aClass = ((PsiClassType)type).resolve(); - if(aClass == null) return null; - if("java.util.OptionalInt".equals(aClass.getQualifiedName())) { - return PsiType.INT; - } - if("java.util.OptionalLong".equals(aClass.getQualifiedName())) { - return PsiType.LONG; - } - if("java.util.OptionalDouble".equals(aClass.getQualifiedName())) { - return PsiType.DOUBLE; - } - if(!CommonClassNames.JAVA_UTIL_OPTIONAL.equals(aClass.getQualifiedName())) return null; - PsiType[] parameters = ((PsiClassType)type).getParameters(); - if(parameters.length != 1) return null; - PsiType streamType = parameters[0]; - if(streamType instanceof PsiCapturedWildcardType) { - streamType = ((PsiCapturedWildcardType)streamType).getUpperBound(); - } - return streamType; - } - static class ReduceTerminalOperation extends TerminalOperation { private PsiExpression myIdentity; private String myType; @@ -261,7 +222,7 @@ abstract class TerminalOperation extends Operation { String seen = context.declare("seen", "boolean", "false"); String accumulator = context.declareResult("acc", myType, TypeConversionUtil.isPrimitive(myType) ? "0" : "null"); myUpdater.transform(context, accumulator, inVar.getName()); - String optionalClass = getOptionalClass(myType); + String optionalClass = OptionalUtil.getOptionalClass(myType); context.setFinisher("(" + seen + "?" + optionalClass + ".of(" + accumulator + "):" + optionalClass + ".empty())"); return "if(!" + seen + ") {\n" + seen + "=true;\n" + diff --git a/java/java-impl/src/com/intellij/codeInspection/util/OptionalUtil.java b/java/java-impl/src/com/intellij/codeInspection/util/OptionalUtil.java new file mode 100644 index 000000000000..9a8714839710 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInspection/util/OptionalUtil.java @@ -0,0 +1,159 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInspection.util; + +import com.intellij.codeInsight.PsiEquivalenceUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.util.RefactoringUtil; +import com.siyeh.ig.psiutils.ExpressionUtils; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +/** + * @author Tagir Valeev + */ +public class OptionalUtil { + @NotNull + @Contract(pure = true) + public static String getOptionalClass(String type) { + switch (type) { + case "int": + return "java.util.OptionalInt"; + case "long": + return "java.util.OptionalLong"; + case "double": + return "java.util.OptionalDouble"; + default: + return CommonClassNames.JAVA_UTIL_OPTIONAL; + } + } + + @Contract("null -> null") + public static PsiType getOptionalElementType(PsiType type) { + PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type); + if(aClass == null) return null; + String className = aClass.getQualifiedName(); + if(className == null) return null; + switch (className) { + case "java.util.OptionalInt": + return PsiType.INT; + case "java.util.OptionalLong": + return PsiType.LONG; + case "java.util.OptionalDouble": + return PsiType.DOUBLE; + case CommonClassNames.JAVA_UTIL_OPTIONAL: + PsiType[] parameters = ((PsiClassType)type).getParameters(); + if (parameters.length != 1) return null; + PsiType streamType = parameters[0]; + if (streamType instanceof PsiCapturedWildcardType) { + streamType = ((PsiCapturedWildcardType)streamType).getUpperBound(); + } + return streamType; + default: + return null; + } + } + + static boolean isOptionalEmptyCall(PsiMethodCallExpression call) { + if ("empty".equals(call.getMethodExpression().getReferenceName())) { + PsiExpression[] args = call.getArgumentList().getExpressions(); + if(args.length == 0) { + PsiMethod method = call.resolveMethod(); + if (method != null && method.getParameterList().getParametersCount() == 0) { + PsiClass aClass = method.getContainingClass(); + if(aClass != null && CommonClassNames.JAVA_UTIL_OPTIONAL.equals(aClass.getQualifiedName())) { + return true; + } + } + } + } + return false; + } + + static boolean isOptionalOfCall(PsiMethodCallExpression call) { + if ("of".equals(call.getMethodExpression().getReferenceName())) { + PsiExpression[] args = call.getArgumentList().getExpressions(); + if(args.length == 1) { + PsiMethod method = call.resolveMethod(); + if (method != null && method.getParameterList().getParametersCount() == 1) { + PsiClass aClass = method.getContainingClass(); + if(aClass != null && CommonClassNames.JAVA_UTIL_OPTIONAL.equals(aClass.getQualifiedName())) { + return true; + } + } + } + } + return false; + } + + /** + * Generates an expression text which will unwrap an {@link java.util.Optional}. + * + * @param qualifier the text representing a qualifier of Optional type + * @param var a variable used to refer optional value inside {@code trueExpression} + * @param trueExpression an expression which should be evaluated if Optional is non-empty + * @param falseExpression an expression which should be returned if Optional is empty + * @param targetType a type of target expression + * @param useOrElseGet if true, use orElseGet if necessary + * @return an expression text which will unwrap an {@code Optional}. + */ + public static String generateOptionalUnwrap(String qualifier, PsiVariable var, + PsiExpression trueExpression, PsiExpression falseExpression, + PsiType targetType, boolean useOrElseGet) { + if (!ExpressionUtils.isIdentityMapping(var, trueExpression)) { + if(trueExpression instanceof PsiTypeCastExpression && ExpressionUtils.isNullLiteral(falseExpression)) { + PsiTypeCastExpression castExpression = (PsiTypeCastExpression)trueExpression; + PsiTypeElement castType = castExpression.getCastType(); + // pull cast outside to avoid the .map() step + if(castType != null && ExpressionUtils.isIdentityMapping(var, castExpression.getOperand())) { + return "(" + castType.getText() + ")" + qualifier + ".orElse(null)"; + } + } + if(ExpressionUtils.isLiteral(falseExpression, Boolean.FALSE) && PsiType.BOOLEAN.equals(trueExpression.getType())) { + return qualifier + ".filter(" + LambdaUtil.createLambda(var, trueExpression) + ").isPresent()"; + } + if(trueExpression instanceof PsiConditionalExpression) { + PsiConditionalExpression condition = (PsiConditionalExpression)trueExpression; + PsiExpression elseExpression = condition.getElseExpression(); + if(elseExpression != null && PsiEquivalenceUtil.areElementsEquivalent(falseExpression, elseExpression)) { + return generateOptionalUnwrap( + qualifier + ".filter(" + LambdaUtil.createLambda(var, condition.getCondition()) + ")", var, + condition.getThenExpression(), falseExpression, targetType, useOrElseGet); + } + } + if(falseExpression instanceof PsiMethodCallExpression && isOptionalEmptyCall((PsiMethodCallExpression)falseExpression)) { + // simplify "qualifier.map(x -> Optional.of(x)).orElse(Optional.empty())" to "qualifier" + if (trueExpression instanceof PsiMethodCallExpression && isOptionalOfCall((PsiMethodCallExpression)trueExpression)) { + PsiExpression arg = ((PsiMethodCallExpression)trueExpression).getArgumentList().getExpressions()[0]; + if(ExpressionUtils.isIdentityMapping(var, arg)) { + return qualifier; + } + return qualifier + ".map(" + LambdaUtil.createLambda(var, arg) + ")"; + } + return qualifier + ".flatMap(" + LambdaUtil.createLambda(var, trueExpression) + ")"; + } + trueExpression = + targetType == null ? trueExpression : RefactoringUtil.convertInitializerToNormalExpression(trueExpression, targetType); + qualifier += ".map(" + LambdaUtil.createLambda(var, trueExpression) + ")"; + } + if (useOrElseGet && !ExpressionUtils.isSimpleExpression(falseExpression)) { + return qualifier + ".orElseGet(() -> " + falseExpression.getText() + ")"; + } else { + return qualifier + ".orElse(" + falseExpression.getText() + ")"; + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignment.java index a1fe6d52b2f5..cb72dbe8ff70 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignment.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentField.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentField.java index 91132446dd73..e9bb12b01d4f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentField.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentField.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java index 6d07d1bfd856..a097e38e57e1 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMapOrElseGet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMapOrElseGet.java index decd3ee7e70a..f4a155e6ad68 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMapOrElseGet.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMapOrElseGet.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElseGet()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java index 8f846857ceb2..fba7408b5a4e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with ifPresent()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerField.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerField.java index 8a4f6b52c7b7..57bb5a8769a4 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerField.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerField.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with ifPresent()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturn.java index 1c0ba2d15786..46b5da34eeb9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturn.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturn.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnCast.java new file mode 100644 index 000000000000..069b2eaa70d7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnCast.java @@ -0,0 +1,16 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + private static String test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return (String) first.orElse(null); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java index 73b28dd516d9..07ee230d09cd 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnList.java index 7af450477ef1..0d5213210a5b 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnList.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnList.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnNot.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnNot.java index 1c0ba2d15786..46b5da34eeb9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnNot.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnNot.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnSimple.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnSimple.java index 00073c166db9..32af6d50b5ad 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnSimple.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnSimple.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterSelfAsEmpty.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterSelfAsEmpty.java new file mode 100644 index 000000000000..0032f2e4f500 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterSelfAsEmpty.java @@ -0,0 +1,12 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Optional; + +public class Main { + public Optional get() { + Optional port = Optional.ofNullable(System.getProperty("abc"); + Optional result; + result = port.map(String::trim); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernary.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernary.java new file mode 100644 index 000000000000..70cbb3f5b4d1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernary.java @@ -0,0 +1,16 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + private static String test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return (String) first.orElse(null); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryFlatMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryFlatMap.java new file mode 100644 index 000000000000..8a5275a1d438 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryFlatMap.java @@ -0,0 +1,20 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + public static Optional trimmed(String s) { + return s.isEmpty() ? Optional.empty() : Optional.of(s.trim()); + } + + private static Optional test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return first.flatMap(o -> trimmed((String) o)); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryNegatedMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryNegatedMap.java new file mode 100644 index 000000000000..a8e0bff56990 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryNegatedMap.java @@ -0,0 +1,16 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + private static Optional test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return first.map(o -> (String) o); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryOptional.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryOptional.java new file mode 100644 index 000000000000..f7c5cd0d1eea --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterTernaryOptional.java @@ -0,0 +1,16 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + private static Optional test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return first; + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignment.java index 666f8683ac31..3887921d6d46 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignment.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentField.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentField.java index c3ee364fca95..56efbb89896e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentField.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentField.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java index 23ca35a23f77..b22119c8d5ec 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMapOrElseGet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMapOrElseGet.java index a2d05f785297..c678bfe377f3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMapOrElseGet.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMapOrElseGet.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElseGet()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java index 346fa13a5be7..c8bd21c05e06 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with ifPresent()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerField.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerField.java index fc19e11fd821..cecea1887d42 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerField.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerField.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with ifPresent()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNoGet.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNoGet.java index 307dc2964009..1cb6aa4b7810 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNoGet.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNoGet.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with ifPresent()" "false" +// "Replace Optional.isPresent() condition with functional style expression" "false" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java index 3b768999b226..e62b7210bfee 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with ifPresent()" "false" +// "Replace Optional.isPresent() condition with functional style expression" "false" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturn.java index 8f14646a48a5..1a0f428b7f88 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturn.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturn.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnCast.java new file mode 100644 index 000000000000..848c9d906f57 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnCast.java @@ -0,0 +1,19 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + private static String test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + if(first.isPresent()) { + return (String)first.get(); + } + return null; + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnComments.java index 2136c47fae92..699624e19fce 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnComments.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnComments.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnInterrupted.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnInterrupted.java index 2a873f5dff9e..aa0701b33d0c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnInterrupted.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnInterrupted.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "false" +// "Replace Optional.isPresent() condition with functional style expression" "false" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnList.java index e78d45bfc48e..073d2f26696f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnList.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnList.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnNonFinalUsed.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnNonFinalUsed.java index d016ce8335ee..0bd0f4476f0c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnNonFinalUsed.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnNonFinalUsed.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "false" +// "Replace Optional.isPresent() condition with functional style expression" "false" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnNot.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnNot.java index abd1344999f2..c7b2c0934e60 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnNot.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnNot.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnRaw.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnRaw.java index 0d13d3c3e7dd..6b7ec47bc654 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnRaw.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnRaw.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with map().orElse()" "false" +// "Replace Optional.isPresent() condition with functional style expression" "false" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnSimple.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnSimple.java index 6555b66fd5a6..c1659248ffd5 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnSimple.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeReturnSimple.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with orElse()" "true" +// "Replace Optional.isPresent() condition with functional style expression" "true" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeSelfAsEmpty.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeSelfAsEmpty.java new file mode 100644 index 000000000000..9eae8c0ebe57 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeSelfAsEmpty.java @@ -0,0 +1,16 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Optional; + +public class Main { + public Optional get() { + Optional port = Optional.ofNullable(System.getProperty("abc"); + Optional result; + if(port.isPresent()) { + result = Optional.of(port.get().trim()); + } else { + result = port; + } + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernary.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernary.java new file mode 100644 index 000000000000..be2bead547ca --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernary.java @@ -0,0 +1,16 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + private static String test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return first.isPresent() ? (String) first.get() : null; + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryFlatMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryFlatMap.java new file mode 100644 index 000000000000..37d4b36992e5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryFlatMap.java @@ -0,0 +1,20 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + public static Optional trimmed(String s) { + return s.isEmpty() ? Optional.empty() : Optional.of(s.trim()); + } + + private static Optional test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return first.isPresent() ? trimmed((String) first.get()) : Optional.empty(); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryNegatedMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryNegatedMap.java new file mode 100644 index 000000000000..9741b8aa3eda --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryNegatedMap.java @@ -0,0 +1,16 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + private static Optional test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return !first.isPresent() ? Optional.empty() : Optional.of((String) first.get()); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryOptional.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryOptional.java new file mode 100644 index 000000000000..55339723ac5d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeTernaryOptional.java @@ -0,0 +1,16 @@ +// "Replace Optional.isPresent() condition with functional style expression" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class Main { + private static Optional test(List list) { + Optional first = list.stream().filter(obj -> obj instanceof String).findFirst(); + return first.isPresent() ? Optional.of(first.get()) : Optional.empty(); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFindFirstOptional.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFindFirstOptional.java new file mode 100644 index 000000000000..fc003545d7f6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFindFirstOptional.java @@ -0,0 +1,17 @@ +// "Replace with findFirst()" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class Main { + private static String test(List list) { + Optional found = list.stream().filter(Objects::nonNull).findFirst(); + return found.orElse(null); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFindFirstOptionalFlatMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFindFirstOptionalFlatMap.java new file mode 100644 index 000000000000..0943c651558a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFindFirstOptionalFlatMap.java @@ -0,0 +1,15 @@ +// "Replace with findFirst()" "true" + +import java.util.List; +import java.util.Optional; + +public class Main { + public Optional trim(String s) { + return s.isEmpty() ? Optional.empty() : Optional.of(s.trim()); + } + + public Optional test(List objects) { + Optional result = objects.stream().filter(obj -> obj instanceof String).findFirst().flatMap(obj -> trim((String) obj)); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstOptional.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstOptional.java new file mode 100644 index 000000000000..c97e629fb31e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstOptional.java @@ -0,0 +1,23 @@ +// "Replace with findFirst()" "true" + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class Main { + private static String test(List list) { + Optional found = Optional.empty(); + for (String s : list) { + if (Objects.nonNull(s)) { + found = Optional.of(s); + break; + } + } + return found.orElse(null); + } + + public static void main(String[] args) { + System.out.println(test(Arrays.asList(null, null, "aa", "bbb", "c", null, "dd"))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstOptionalFlatMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstOptionalFlatMap.java new file mode 100644 index 000000000000..689c43181078 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFindFirstOptionalFlatMap.java @@ -0,0 +1,21 @@ +// "Replace with findFirst()" "true" + +import java.util.List; +import java.util.Optional; + +public class Main { + public Optional trim(String s) { + return s.isEmpty() ? Optional.empty() : Optional.of(s.trim()); + } + + public Optional test(List objects) { + Optional result = Optional.empty(); + for(Object obj : objects) { + if(obj instanceof String) { + result = trim((String)obj); + break; + } + } + return result; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java index 79dce6875f45..f1d34f1260dd 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java @@ -792,4 +792,9 @@ public class ExpressionUtils { } return true; } + + @Contract("_, null -> false") + public static boolean isIdentityMapping(PsiVariable variable, PsiExpression mapperCall) { + return mapperCall instanceof PsiReferenceExpression && ((PsiReferenceExpression)mapperCall).isReferenceTo(variable); + } } \ No newline at end of file