JavaDoc for OptionalUtil#getOptionalElementType; MethodCallUtils#isCallToStaticMethod created and used; ExpressionUtils#isIdentityMapping -> isReferenceTo; used where applicable (IDEA-CR-15464).

This commit is contained in:
Tagir Valeev
2016-11-08 10:19:29 +07:00
parent 75c134d363
commit 1227db0d42
9 changed files with 58 additions and 63 deletions
@@ -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();
@@ -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],
@@ -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));
@@ -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);
@@ -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<String>} 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) + ")";
@@ -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 {