From 1227db0d4247e40a08de095d84df51f75de443e6 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 8 Nov 2016 10:16:52 +0700 Subject: [PATCH] JavaDoc for OptionalUtil#getOptionalElementType; MethodCallUtils#isCallToStaticMethod created and used; ExpressionUtils#isIdentityMapping -> isReferenceTo; used where applicable (IDEA-CR-15464). --- ...SimplifyStreamApiCallChainsInspection.java | 5 +- ...anBeReplacedWithConstructorInspection.java | 15 +++--- .../OptionalIsPresentInspection.java | 2 +- .../ReplaceWithFindFirstFix.java | 3 +- .../StreamApiMigrationInspection.java | 11 ++-- .../codeInspection/util/OptionalUtil.java | 53 ++++++------------- .../MoveInstanceMethodProcessor.java | 10 ++-- .../siyeh/ig/psiutils/ExpressionUtils.java | 7 +-- .../siyeh/ig/psiutils/MethodCallUtils.java | 15 ++++++ 9 files changed, 58 insertions(+), 63 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java index ea1cd373486b..e24dd96672ee 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java @@ -25,6 +25,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.impl.PsiDiamondTypeUtil; import com.intellij.psi.util.*; import com.siyeh.ig.psiutils.BoolUtils; +import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.StreamApiUtil; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nls; @@ -178,14 +179,14 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns PsiParameter parameter = parameters[0]; PsiExpression expression = PsiUtil.skipParenthesizedExprDown(LambdaUtil.extractSingleExpressionFromBody(lambda.getBody())); // x -> x - if(expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).isReferenceTo(parameter)) { + if(ExpressionUtils.isReferenceTo(expression, parameter)) { return true; } if(expression instanceof PsiCallExpression) { PsiExpressionList list = ((PsiCallExpression)expression).getArgumentList(); if(list == null) return false; PsiExpression[] args = list.getExpressions(); - if(args.length != 1 || !(args[0] instanceof PsiReferenceExpression) || !(((PsiReferenceExpression)args[0]).isReferenceTo(parameter))) { + if(args.length != 1 || !ExpressionUtils.isReferenceTo(args[0], parameter)) { return false; } // x -> new Integer(x) diff --git a/java/java-impl/src/com/intellij/codeInspection/CollectionAddAllCanBeReplacedWithConstructorInspection.java b/java/java-impl/src/com/intellij/codeInspection/CollectionAddAllCanBeReplacedWithConstructorInspection.java index 27c4e6958bf5..78c931856ce2 100644 --- a/java/java-impl/src/com/intellij/codeInspection/CollectionAddAllCanBeReplacedWithConstructorInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/CollectionAddAllCanBeReplacedWithConstructorInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -20,17 +20,19 @@ import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.*; import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.performance.CollectionsListSettings; +import com.siyeh.ig.psiutils.ExpressionUtils; import org.jdom.Element; -import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -196,8 +198,7 @@ public class CollectionAddAllCanBeReplacedWithConstructorInspection extends Base return Pair.create(true, null); } for (PsiAssignmentExpression expression : PsiTreeUtil.findChildrenOfType(currentStatement, PsiAssignmentExpression.class)) { - final PsiExpression lExpression = expression.getLExpression(); - if (lExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)lExpression).isReferenceTo(localVariable)) { + if (ExpressionUtils.isReferenceTo(expression.getLExpression(), localVariable)) { final PsiExpression rExpression = expression.getRExpression(); final boolean isValid = checkLocalVariableAssignmentOrInitializer(rExpression); return Pair.create(isValid, isValid ? (PsiNewExpression)rExpression : null); @@ -207,7 +208,7 @@ public class CollectionAddAllCanBeReplacedWithConstructorInspection extends Base return Pair.create(true, null); } - private boolean isAddAllReplaceable(final PsiExpression addAllExpression, PsiNewExpression newExpression) { + private static boolean isAddAllReplaceable(final PsiExpression addAllExpression, PsiNewExpression newExpression) { final boolean[] isReplaceable = new boolean[]{true}; final PsiFile newExpressionContainingFile = newExpression.getContainingFile(); final TextRange newExpressionTextRange = newExpression.getTextRange(); diff --git a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java index dbb036e1ce65..bb4a8899402a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java @@ -198,7 +198,7 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo PsiExpression falseValue) { String lambdaText = generateOptionalLambda(factory, optionalVariable, trueValue); PsiLambdaExpression lambda = (PsiLambdaExpression)factory.createExpressionFromText(lambdaText, trueValue); - if(falseValue instanceof PsiReferenceExpression && ((PsiReferenceExpression)falseValue).isReferenceTo(optionalVariable)) { + if(ExpressionUtils.isReferenceTo(falseValue, optionalVariable)) { falseValue = factory.createExpressionFromText(CommonClassNames.JAVA_UTIL_OPTIONAL+".empty()", falseValue); } return OptionalUtil.generateOptionalUnwrap(optionalVariable.getName(), lambda.getParameterList().getParameters()[0], 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 f1213a5bef9a..6fac566422a8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithFindFirstFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/ReplaceWithFindFirstFix.java @@ -90,8 +90,7 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix { ExpressionUtils.getAssignment(PsiTreeUtil.skipSiblingsBackward(loopStatement, PsiWhiteSpace.class, PsiComment.class)); if(previousAssignment != null) { PsiExpression prevRValue = previousAssignment.getRExpression(); - PsiExpression prevLValue = previousAssignment.getLExpression(); - if(prevRValue != null && prevLValue instanceof PsiReferenceExpression && ((PsiReferenceExpression)prevLValue).isReferenceTo(var)) { + if(prevRValue != null && ExpressionUtils.isReferenceTo(previousAssignment.getLExpression(), var)) { previousAssignment.delete(); return loopStatement.replace(elementFactory.createStatementFromText( var.getName() + " = " + generateOptionalUnwrap(stream, tb, value, prevRValue, var.getType()) + ";", loopStatement)); 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 32d594f56461..ab536a464e2d 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 (!ExpressionUtils.isIdentityMapping(variable, methodCallExpression.getArgumentList().getExpressions()[0])) return false; + if (!ExpressionUtils.isReferenceTo(methodCallExpression.getArgumentList().getExpressions()[0], variable)) return false; PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); if(qualifierExpression == null || qualifierExpression instanceof PsiThisExpression) { PsiMethod method = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethod.class); @@ -666,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 && !ExpressionUtils.isIdentityMapping(tb.getVariable(), rValue)) return; + if(tb.getVariable().getType() instanceof PsiPrimitiveType && !ExpressionUtils.isReferenceTo(rValue, tb.getVariable())) return; registerProblem(statement, "findFirst", new ReplaceWithFindFirstFix()); } } @@ -713,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) || ExpressionUtils.isIdentityMapping(tb.getVariable(), value))) { + && (!(tb.getVariable().getType() instanceof PsiPrimitiveType) || ExpressionUtils.isReferenceTo(value, tb.getVariable()))) { registerProblem(statement, "findFirst", new ReplaceWithFindFirstFix()); } } @@ -968,7 +968,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo @Override public String createReplacement() { - if (ExpressionUtils.isIdentityMapping(myVariable, myExpression)) { + if (ExpressionUtils.isReferenceTo(myExpression, myVariable)) { if (!(myType instanceof PsiPrimitiveType)) { return myVariable.getType() instanceof PsiPrimitiveType ? ".boxed()" : ""; } @@ -1440,9 +1440,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(first); if(assignment != null) { - PsiExpression lValue = assignment.getLExpression(); PsiExpression rValue = assignment.getRExpression(); - if(rValue != null && lValue instanceof PsiReferenceExpression && ((PsiReferenceExpression)lValue).isReferenceTo(myVariable)) { + if(rValue != null && ExpressionUtils.isReferenceTo(assignment.getLExpression(), myVariable)) { PsiStatement[] leftOver = Arrays.copyOfRange(myStatements, 1, myStatements.length); MapOp op = new MapOp(myPreviousOp, rValue, myVariable, myVariable.getType()); return new TerminalBlock(op, myVariable, leftOver); diff --git a/java/java-impl/src/com/intellij/codeInspection/util/OptionalUtil.java b/java/java-impl/src/com/intellij/codeInspection/util/OptionalUtil.java index 9a8714839710..13c2bfffc2a9 100644 --- a/java/java-impl/src/com/intellij/codeInspection/util/OptionalUtil.java +++ b/java/java-impl/src/com/intellij/codeInspection/util/OptionalUtil.java @@ -20,6 +20,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.util.RefactoringUtil; import com.siyeh.ig.psiutils.ExpressionUtils; +import com.siyeh.ig.psiutils.MethodCallUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -42,6 +43,14 @@ public class OptionalUtil { } } + /** + * Unwraps an {@link java.util.Optional}, {@link java.util.OptionalInt}, {@link java.util.OptionalLong} or {@link java.util.OptionalDouble} + * returning its element type + * + * @param type a type representing optional (e.g. {@code Optional} or {@code OptionalInt}) + * @return an element type (e.g. {@code String} or {@code int}). Returns {@code null} if the supplied type is not an optional type + * or its a raw {@code java.util.Optional}. + */ @Contract("null -> null") public static PsiType getOptionalElementType(PsiType type) { PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type); @@ -68,38 +77,6 @@ public class OptionalUtil { } } - 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}. * @@ -114,12 +91,12 @@ public class OptionalUtil { public static String generateOptionalUnwrap(String qualifier, PsiVariable var, PsiExpression trueExpression, PsiExpression falseExpression, PsiType targetType, boolean useOrElseGet) { - if (!ExpressionUtils.isIdentityMapping(var, trueExpression)) { + if (!ExpressionUtils.isReferenceTo(trueExpression, var)) { 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())) { + if(castType != null && ExpressionUtils.isReferenceTo(castExpression.getOperand(), var)) { return "(" + castType.getText() + ")" + qualifier + ".orElse(null)"; } } @@ -135,11 +112,13 @@ public class OptionalUtil { condition.getThenExpression(), falseExpression, targetType, useOrElseGet); } } - if(falseExpression instanceof PsiMethodCallExpression && isOptionalEmptyCall((PsiMethodCallExpression)falseExpression)) { + if(falseExpression instanceof PsiMethodCallExpression && + MethodCallUtils.isCallToStaticMethod((PsiMethodCallExpression)falseExpression, CommonClassNames.JAVA_UTIL_OPTIONAL, "empty", 0)) { // simplify "qualifier.map(x -> Optional.of(x)).orElse(Optional.empty())" to "qualifier" - if (trueExpression instanceof PsiMethodCallExpression && isOptionalOfCall((PsiMethodCallExpression)trueExpression)) { + if (trueExpression instanceof PsiMethodCallExpression && + MethodCallUtils.isCallToStaticMethod((PsiMethodCallExpression)trueExpression, CommonClassNames.JAVA_UTIL_OPTIONAL, "of", 1)) { PsiExpression arg = ((PsiMethodCallExpression)trueExpression).getArgumentList().getExpressions()[0]; - if(ExpressionUtils.isIdentityMapping(var, arg)) { + if(ExpressionUtils.isReferenceTo(arg, var)) { return qualifier; } return qualifier + ".map(" + LambdaUtil.createLambda(var, arg) + ")"; diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java index 5584035f94fb..26338d0d79cb 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -41,6 +41,7 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; +import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -382,8 +383,7 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ private PsiExpression replaceRefsToTargetVariable(final PsiExpression expression) { final PsiManager manager = expression.getManager(); - if (expression instanceof PsiReferenceExpression && - ((PsiReferenceExpression)expression).isReferenceTo(myTargetVariable)) { + if (ExpressionUtils.isReferenceTo(expression, myTargetVariable)) { return createThisExpr(manager); } @@ -460,7 +460,7 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ try { final PsiExpression qualifier = expression.getQualifierExpression(); final PsiElement resolved = expression.resolve(); - if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifier).isReferenceTo(myTargetVariable)) { + if (ExpressionUtils.isReferenceTo(qualifier, myTargetVariable)) { if (resolved instanceof PsiField) { for (PsiParameter parameter : myMethod.getParameterList().getParameters()) { if (Comparing.strEqual(parameter.getName(), ((PsiField)resolved).getName())) { @@ -508,7 +508,7 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{ @Override public void visitNewExpression(PsiNewExpression expression) { try { final PsiExpression qualifier = expression.getQualifier(); - if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifier).isReferenceTo(myTargetVariable)) { + if (ExpressionUtils.isReferenceTo(qualifier, myTargetVariable)) { //Target is a field, replace target.new A() -> new A() qualifier.delete(); } else { 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 f1d34f1260dd..9fbb0a0aa114 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java @@ -793,8 +793,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); + @Contract("null, _ -> false; _, null -> false") + public static boolean isReferenceTo(PsiExpression expression, PsiVariable variable) { + expression = PsiUtil.skipParenthesizedExprDown(expression); + return expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).isReferenceTo(variable); } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodCallUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodCallUtils.java index 85cff482b0b8..3c40b42b1936 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodCallUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodCallUtils.java @@ -117,6 +117,21 @@ public class MethodCallUtils { return isCallToMethod(expression, calledOnClassName, returnType, methodName, parameterTypes); } + public static boolean isCallToStaticMethod(@NotNull PsiMethodCallExpression expression, @NonNls @NotNull String calledOnClassName, + @NonNls @NotNull String methodName, int parameterCount) { + if (!methodName.equals(getMethodName(expression)) || expression.getArgumentList().getExpressions().length != parameterCount) { + return false; + } + PsiMethod method = expression.resolveMethod(); + if (method == null || + !method.getModifierList().hasExplicitModifier(PsiModifier.STATIC) || + method.getParameterList().getParametersCount() != parameterCount) { + return false; + } + PsiClass aClass = method.getContainingClass(); + return aClass != null && calledOnClassName.equals(aClass.getQualifiedName()); + } + public static boolean isCallToMethod(@NotNull PsiMethodCallExpression expression, @NonNls @Nullable String calledOnClassName, @Nullable PsiType returnType, @Nullable Pattern methodNamePattern, @Nullable PsiType... parameterTypes) { final PsiReferenceExpression methodExpression = expression.getMethodExpression();