guava type migration: Optional#or parameter migration fixed + simplification of generated code (IDEA-147724)

This commit is contained in:
Dmitry Batkovich
2015-11-12 15:30:20 +03:00
parent 64c8b4f162
commit dc5dc54aca
9 changed files with 112 additions and 22 deletions
@@ -17,7 +17,6 @@ package com.intellij.refactoring.typeMigration.rules.guava;
import com.intellij.codeInspection.AnonymousCanBeLambdaInspection;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
import com.intellij.refactoring.typeMigration.rules.TypeConversionRule;
@@ -27,8 +26,6 @@ import com.intellij.util.containers.hash.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
/**
@@ -59,7 +56,8 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule {
@Nullable
protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression,
@NotNull PsiVariable psiVariable) {
@NotNull PsiVariable psiVariable,
@Nullable PsiExpression context) {
return null;
}
@@ -101,7 +99,7 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule {
else if (context instanceof PsiReferenceExpression) {
final PsiElement resolvedElement = ((PsiReferenceExpression)context).resolve();
if (resolvedElement instanceof PsiVariable) {
return findConversionForVariableReference((PsiReferenceExpression)context, (PsiVariable)resolvedElement);
return findConversionForVariableReference((PsiReferenceExpression)context, (PsiVariable)resolvedElement, context);
}
}
return null;
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.typeMigration.rules.guava;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiReferenceExpression;
import com.intellij.psi.PsiVariable;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
@@ -39,7 +40,7 @@ public class GuavaFunctionConversionRule extends BaseGuavaTypeConversionRule {
@Nullable
@Override
protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression,
@NotNull PsiVariable psiVariable) {
@NotNull PsiVariable psiVariable, PsiExpression context) {
return new TypeConversionDescriptor("$f$", "$f$::apply");
}
@@ -32,6 +32,7 @@ import java.util.Map;
public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule {
private final static Logger LOG = Logger.getInstance(GuavaOptionalConversionRule.class);
public final static String OPTIONAL_CONVERTOR_PATTERN = "Optional.fromNullable($o$.orElse(null))";
public final static String GUAVA_OPTIONAL = "com.google.common.base.Optional";
public final static String JAVA_OPTIONAL = "java.util.Optional";
@@ -46,17 +47,7 @@ public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule {
if (!(context instanceof PsiMethodCallExpression)) {
if ("or".equals(methodName)) {
PsiMethodCallExpression methodCallExpression = null;
if (context instanceof PsiMethodCallExpression) {
final PsiClass aClass = getParameterClass(method);
if (aClass != null) {
final String qName = aClass.getQualifiedName();
String pattern =
GUAVA_OPTIONAL.equals(qName) ? "java.util.Optional.ofNullable($expr$.get())" : "java.util.Optional.ofNullable($expr$)";
return new TypeConversionDescriptor("$expr$", pattern);
}
return null;
}
else if (context.getParent() instanceof PsiMethodCallExpression) {
if (context.getParent() instanceof PsiMethodCallExpression) {
methodCallExpression = (PsiMethodCallExpression)context.getParent();
}
if (methodCallExpression == null) {
@@ -67,7 +58,15 @@ public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule {
final String qName = aClass.getQualifiedName();
if (GUAVA_OPTIONAL.equals(qName)) {
TypeConversionDescriptor descriptor =
new TypeConversionDescriptor("$val$.or($other$)", "java.util.Optional.ofNullable($val$.orElseGet($other$::get))");
new TypeConversionDescriptor(null, "java.util.Optional.ofNullable($val$.orElseGet($o$::get))") {
@Override
public PsiExpression replace(PsiExpression expression) {
setStringToReplace("$val$.or(" +
GuavaOptionalConversionUtil.simplifyParameterPattern((PsiMethodCallExpression)expression)
+ ")");
return super.replace(expression);
}
};
if (to != null) {
descriptor.withConversionType(to);
}
@@ -80,7 +79,7 @@ public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule {
return null;
}
else if ("transform".equals(methodName)) {
final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)(context instanceof PsiMethodCallExpression ? context : context.getParent());
final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)(context.getParent());
final PsiExpression[] arguments = methodCall.getArgumentList().getExpressions();
if (arguments.length != 1) {
return null;
@@ -107,7 +106,11 @@ public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule {
@Nullable
@Override
protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression,
@NotNull PsiVariable psiVariable) {
@NotNull PsiVariable psiVariable,
@Nullable PsiExpression context) {
if (GuavaOptionalConversionUtil.isOptionalOrContext(context)) {
return new TypeConversionDescriptor("$o$", "com.google.common.base." + OPTIONAL_CONVERTOR_PATTERN);
}
return new TypeConversionDescriptor("$o$", "$o$::get");
}
@@ -0,0 +1,68 @@
/*
* Copyright 2000-2015 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.refactoring.typeMigration.rules.guava;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiMatcherExpression;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
import com.intellij.structuralsearch.MatchOptions;
import com.intellij.structuralsearch.MatchResult;
import com.intellij.structuralsearch.Matcher;
import com.intellij.structuralsearch.plugin.replace.impl.Replacer;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author Dmitry Batkovich
*/
public class GuavaOptionalConversionUtil {
static boolean isOptionalOrContext(@Nullable PsiExpression context) {
if (context == null) return false;
final PsiElement parent = context.getParent();
if (parent == null) return false;
final PsiElement maybeMethodCall = parent.getParent();
if (!(maybeMethodCall instanceof PsiMethodCallExpression)) return false;
final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)maybeMethodCall;
final int argumentLength = methodCall.getArgumentList().getExpressions().length;
if (argumentLength != 1) return false;
final PsiMethod resolvedMethod = methodCall.resolveMethod();
if (resolvedMethod == null || !"or".equals(resolvedMethod.getName())) return false;
final PsiClass aClass = resolvedMethod.getContainingClass();
return aClass != null && GuavaOptionalConversionRule.GUAVA_OPTIONAL.equals(aClass.getQualifiedName());
}
static String simplifyParameterPattern(PsiMethodCallExpression methodCall) {
final PsiExpressionList argumentList = methodCall.getArgumentList();
final PsiExpression[] expressions = argumentList.getExpressions();
if (expressions.length == 1) {
final PsiExpression expression = expressions[0];
Matcher matcher = new Matcher(methodCall.getProject());
final MatchOptions options = new MatchOptions();
options.setFileType(StdFileTypes.JAVA);
final List<MatchResult> results =
matcher.testFindMatches(expression.getText(), GuavaOptionalConversionRule.OPTIONAL_CONVERTOR_PATTERN, options, false);
if (!results.isEmpty()) {
final MatchResult result = results.get(0);
if (result.getStart() == 0 && result.getEnd() == -1) {
return GuavaOptionalConversionRule.OPTIONAL_CONVERTOR_PATTERN;
}
}
}
return "$o$";
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.typeMigration.rules.guava;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiReferenceExpression;
import com.intellij.psi.PsiVariable;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
@@ -39,7 +40,7 @@ public class GuavaPredicateConversionRule extends BaseGuavaTypeConversionRule {
@Nullable
@Override
protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression,
@NotNull PsiVariable psiVariable) {
@NotNull PsiVariable psiVariable, PsiExpression context) {
return new TypeConversionDescriptor("$p$", "$p$::test");
}
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.typeMigration.rules.guava;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiReferenceExpression;
import com.intellij.psi.PsiVariable;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
@@ -39,7 +40,7 @@ public class GuavaSupplierConversionRule extends BaseGuavaTypeConversionRule {
@Nullable
@Override
protected TypeConversionDescriptorBase findConversionForVariableReference(@NotNull PsiReferenceExpression referenceExpression,
@NotNull PsiVariable psiVariable) {
@NotNull PsiVariable psiVariable, PsiExpression context) {
return new TypeConversionDescriptor("$f$", "$f$::get");
}
@@ -198,6 +198,10 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase {
doTest();
}
public void testSimplifyOptionalComposition() {
doTest();
}
private void doTestNoQuickFixes(final Class<? extends IntentionAction>... quickFixesClasses) {
myFixture.configureByFile(getTestName(true) + ".java");
myFixture.enableInspections(new GuavaInspection());
@@ -0,0 +1,7 @@
import com.google.common.base.Optional;
class SecondChoice {
public void ors(Opti<caret>onal<String> p1, java.util.Optional<String> p2) {
Optional o = p1.or(Optional.fromNullable(p2.orElse(null)));
}
}
@@ -0,0 +1,7 @@
import java.util.Optional;
class SecondChoice {
public void ors(Optional<String> p1, java.util.Optional<String> p2) {
java.util.Optional<String> o = java.util.Optional.ofNullable(p1.orElseGet(p2::get));
}
}