mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
guava type migration: allows to convert guava's method chains using type migration
This commit is contained in:
+11
-4
@@ -211,10 +211,12 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
|
||||
.createExpressionFromText("new " + expectedType.getCanonicalText() + "[]{" + anonymousClass.getText() + "}", anonymousClass);
|
||||
PsiArrayInitializerExpression initializer = newArrayExpression.getArrayInitializer();
|
||||
LOG.assertTrue(initializer != null);
|
||||
return replacePsiElementWithLambda(initializer.getInitializers()[0], true);
|
||||
return replacePsiElementWithLambda(initializer.getInitializers()[0], true, false);
|
||||
}
|
||||
|
||||
public static PsiExpression replacePsiElementWithLambda(@NotNull PsiElement element, final boolean ignoreEqualsMethod) {
|
||||
public static PsiExpression replacePsiElementWithLambda(@NotNull PsiElement element,
|
||||
final boolean ignoreEqualsMethod,
|
||||
boolean forceIgnoreTypeCast) {
|
||||
if (element instanceof PsiNewExpression) {
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return null;
|
||||
final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass();
|
||||
@@ -282,6 +284,11 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
|
||||
}
|
||||
ChangeContextUtil.decodeContextInfo(lambdaExpression, null, null);
|
||||
|
||||
final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
if (forceIgnoreTypeCast) {
|
||||
return (PsiExpression)javaCodeStyleManager.shortenClassReferences(elementFactory.createExpressionFromText(withoutTypesDeclared, lambdaExpression));
|
||||
}
|
||||
|
||||
PsiTypeCastExpression typeCast = (PsiTypeCastExpression)elementFactory
|
||||
.createExpressionFromText("(" + canonicalText + ")" + withoutTypesDeclared, lambdaExpression);
|
||||
final PsiExpression typeCastOperand = typeCast.getOperand();
|
||||
@@ -298,7 +305,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
|
||||
LOG.assertTrue(operand != null);
|
||||
return (PsiExpression)typeCast.replace(operand);
|
||||
}
|
||||
return (PsiExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(typeCast);
|
||||
return (PsiExpression)javaCodeStyleManager.shortenClassReferences(typeCast);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -320,7 +327,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
if (element != null) {
|
||||
replacePsiElementWithLambda(element, false);
|
||||
replacePsiElementWithLambda(element, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ public class GuavaFunctionAndPredicateConverter {
|
||||
if (expression instanceof PsiNewExpression) {
|
||||
final PsiAnonymousClass anonymousClass = ((PsiNewExpression)expression).getAnonymousClass();
|
||||
if (anonymousClass != null && AnonymousCanBeLambdaInspection.canBeConvertedToLambda(anonymousClass, true)) {
|
||||
final PsiExpression lambdaExpression = AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true);
|
||||
final PsiExpression lambdaExpression = AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true, true);
|
||||
LOG.assertTrue(lambdaExpression != null);
|
||||
return lambdaExpression.getText();
|
||||
}
|
||||
|
||||
+24
-9
@@ -16,8 +16,7 @@
|
||||
package com.intellij.refactoring.typeMigration.inspections;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.VariableTypeFix;
|
||||
import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.AtomicNotNullLazyValue;
|
||||
@@ -32,7 +31,8 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,9 @@ import java.util.Map;
|
||||
*/
|
||||
@SuppressWarnings("DialogTitleCapitalization")
|
||||
public class GuavaInspection extends BaseJavaLocalInspectionTool {
|
||||
private final static String PROBLEM_DESCRIPTION = "Guava's functional primitives can be replaced by Java API";
|
||||
private final static Logger LOG = Logger.getInstance(GuavaInspection.class);
|
||||
|
||||
private final static String PROBLEM_DESCRIPTION_FOR_VARIABLE = "Guava's functional primitives can be replaced by Java API";
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -84,15 +86,28 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool {
|
||||
final String qName = psiClass.getQualifiedName();
|
||||
final PsiClass targetClass = myGuavaClassConversions.getValue().get(qName);
|
||||
if (targetClass != null) {
|
||||
final Collection<PsiType> typeParameters = resolveResult.getSubstitutor().getSubstitutionMap().values();
|
||||
final PsiClassType targetType =
|
||||
JavaPsiFacade.getElementFactory(holder.getProject()).createType(targetClass, typeParameters.toArray(new PsiType[typeParameters.size()]));
|
||||
final VariableTypeFix fix = TypeMigrationVariableTypeFixProvider.createTypeMigrationFix(variable, targetType);
|
||||
holder.registerProblem(variable, PROBLEM_DESCRIPTION, fix);
|
||||
final VariableTypeFix fix = TypeMigrationVariableTypeFixProvider.createTypeMigrationFix(variable, addTypeParameters(type, resolveResult, targetClass));
|
||||
holder.registerProblem(variable, PROBLEM_DESCRIPTION_FOR_VARIABLE, fix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PsiClassType addTypeParameters(PsiType currentType, PsiClassType.ClassResolveResult currentTypeResolveResult, PsiClass targetClass) {
|
||||
final Map<PsiTypeParameter, PsiType> substitutionMap = currentTypeResolveResult.getSubstitutor().getSubstitutionMap();
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(holder.getProject());
|
||||
if (substitutionMap.size() == 1) {
|
||||
return elementFactory.createType(targetClass, ContainerUtil.getFirstItem(substitutionMap.values()));
|
||||
} else {
|
||||
LOG.assertTrue(substitutionMap.size() == 2);
|
||||
LOG.assertTrue(GuavaFunctionConversionRule.JAVA_UTIL_FUNCTION_FUNCTION.equals(targetClass.getQualifiedName()));
|
||||
final PsiType returnType = LambdaUtil.getFunctionalInterfaceReturnType(currentType);
|
||||
final List<PsiType> types = new ArrayList<PsiType>(substitutionMap.values());
|
||||
types.remove(returnType);
|
||||
final PsiType parameterType = types.get(0);
|
||||
return elementFactory.createType(targetClass, parameterType, returnType);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -42,7 +42,7 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule {
|
||||
}
|
||||
};
|
||||
|
||||
protected abstract void fillSimpleDescriptors(Map<String, TypeConversionDescriptorBase> descriptorsMap);
|
||||
protected void fillSimpleDescriptors(Map<String, TypeConversionDescriptorBase> descriptorsMap) {};
|
||||
|
||||
@Nullable
|
||||
protected TypeConversionDescriptorBase findConversionForMethod(@NotNull PsiType from,
|
||||
@@ -84,7 +84,7 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule {
|
||||
return new TypeConversionDescriptorBase() {
|
||||
@Override
|
||||
public PsiExpression replace(PsiExpression expression) throws IncorrectOperationException {
|
||||
return AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, false);
|
||||
return AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, false, true);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
+48
-29
@@ -16,9 +16,13 @@
|
||||
package com.intellij.refactoring.typeMigration.rules.guava;
|
||||
|
||||
import com.intellij.codeInspection.java18StreamApi.StreamApiConstants;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
|
||||
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
|
||||
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -26,42 +30,57 @@ import java.util.Map;
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRule {
|
||||
private static final Map<String, TypeConversionDescriptorBase> DESCRIPTORS_MAP = new HashMap<String, TypeConversionDescriptorBase>();
|
||||
|
||||
public static final String FLUENT_ITERABLE = "com.google.common.collect.FluentIterable";
|
||||
|
||||
static {
|
||||
DESCRIPTORS_MAP.put("contains",
|
||||
new TypeConversionDescriptor("$it$.contains($o$)", "$it$.anyMatch(e -> e != null && e.equals(%s))"));
|
||||
DESCRIPTORS_MAP.put("from", new TypeConversionDescriptor("FluentIterable.from($it$)", "$it$.stream()"));
|
||||
DESCRIPTORS_MAP.put("isEmpty", new TypeConversionDescriptor("$q$.isEmpty()", "$q$.findAny().isPresent()"));
|
||||
DESCRIPTORS_MAP.put("skip", new TypeConversionDescriptor("$q$.skip($p$)", "$q$.skip($p$)"));
|
||||
DESCRIPTORS_MAP.put("limit", new TypeConversionDescriptor("$q$.limit($p$)", "$q$.limit($p$)"));
|
||||
DESCRIPTORS_MAP.put("first", new TypeConversionDescriptor("$q$.first()", "$q$.findFirst()"));
|
||||
DESCRIPTORS_MAP.put("transform", new LambdaParametersTypeConversionDescription("$q$.transform($params$)", "$q$.map($params$)"));
|
||||
//TODO support
|
||||
//DESCRIPTORS_MAP.put("transformAndConcat", new TransformAndConcatDescriptorBase("$q$.transformAndConcat($params$)", "$q$.flatMap($params$)"));
|
||||
|
||||
DESCRIPTORS_MAP.put("allMatch", new LambdaParametersTypeConversionDescription("$it$.allMatch($c$)", "$it$." + StreamApiConstants.ALL_MATCH + "($c$)"));
|
||||
DESCRIPTORS_MAP.put("anyMatch", new LambdaParametersTypeConversionDescription("$it$.anyMatch($c$)", "$it$." + StreamApiConstants.ANY_MATCH + "($c$)"));
|
||||
|
||||
//TODO add another filter processor
|
||||
DESCRIPTORS_MAP.put("filter", new LambdaParametersTypeConversionDescription("$it$.filter($p$)", "$it$." + StreamApiConstants.FILTER + "($p$)"));
|
||||
DESCRIPTORS_MAP.put("first", new TypeConversionDescriptor("$it$.first()", "$it$." + StreamApiConstants.FIND_FIRST + "()"));
|
||||
DESCRIPTORS_MAP.put("firstMatch", new LambdaParametersTypeConversionDescription("$it$.firstMatch($p$)", "$it$.filter($p$).findFirst()"));
|
||||
DESCRIPTORS_MAP.put("get", new TypeConversionDescriptor("$it$.get($p$)", "$it$.collect(java.util.stream.Collectors.toList()).get($p$)"));
|
||||
DESCRIPTORS_MAP.put("size", new TypeConversionDescriptor("$it$.size()", "$it$.collect(java.util.stream.Collectors.toList()).size()"));
|
||||
|
||||
DESCRIPTORS_MAP.put("toMap", new TypeConversionDescriptor("$it$.toMap($f$)",
|
||||
"$it$.collect(java.util.stream.Collectors.toMap(java.util.function.Function.identity(), $f$))"));
|
||||
DESCRIPTORS_MAP.put("toList", new TypeConversionDescriptor("$it$.toList()", "$it$.collect(java.util.stream.Collectors.toList())"));
|
||||
DESCRIPTORS_MAP.put("toSet", new TypeConversionDescriptor("$it$.toSet()", "$it$.collect(java.util.stream.Collectors.toSet())"));
|
||||
DESCRIPTORS_MAP.put("toSortedList", new TypeConversionDescriptor("$it$.toSortedList($c$)", "$it$.sorted($c$).collect(java.util.stream.Collectors.toList())"));
|
||||
DESCRIPTORS_MAP.put("toSortedSet", new TypeConversionDescriptor("$it$.toSortedSet($c$)", "$it$.sorted($c$).collect(java.util.stream.Collectors.toSet())"));
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected void fillSimpleDescriptors(Map<String, TypeConversionDescriptorBase> descriptorsMap) {
|
||||
descriptorsMap.put("contains",
|
||||
new TypeConversionDescriptor("$it$.contains($o$)", "$it$.anyMatch(e -> e != null && e.equals(%s))"));
|
||||
descriptorsMap.put("from", new TypeConversionDescriptor("FluentIterable.from($it$)", "$it$.stream()"));
|
||||
descriptorsMap.put("isEmpty", new TypeConversionDescriptor("$q$.isEmpty()", "$q$.findAny().isPresent()"));
|
||||
descriptorsMap.put("skip", new TypeConversionDescriptorBase());
|
||||
descriptorsMap.put("limit", new TypeConversionDescriptorBase());
|
||||
descriptorsMap.put("transform", new LambdaParametersTypeConversionDescription("$q$.transform($params$)", "$q$.map($params$)"));
|
||||
descriptorsMap.put("transformAndConcat",
|
||||
new LambdaParametersTypeConversionDescription("$q$.transformAndConcat($params$)", "$q$.flatMap($params$)"));
|
||||
descriptorsMap.put("first", new TypeConversionDescriptor("$q$.first()", "$q$.findFirst()"));
|
||||
|
||||
descriptorsMap.put("allMatch", new TypeConversionDescriptor("$it$.allMatch($c$)", "$it$." + StreamApiConstants.ALL_MATCH + "($c$)"));
|
||||
descriptorsMap.put("anyMatch", new TypeConversionDescriptor("$it$.anyMatch($c$)", "$it$." + StreamApiConstants.ANY_MATCH + "($c$)"));
|
||||
|
||||
descriptorsMap.put("filter", new TypeConversionDescriptor("$it$.filter($p$)", "$it$." + StreamApiConstants.FILTER + "($p$)"));
|
||||
descriptorsMap.put("first", new TypeConversionDescriptor("$it$.first()", "$it$." + StreamApiConstants.FIND_FIRST + "()"));
|
||||
descriptorsMap.put("firstMatch", new TypeConversionDescriptor("$it$.firstMatch($p$)", "$it$.filter($p$).findFirst()"));
|
||||
descriptorsMap.put("get", new TypeConversionDescriptor("$it$.get($p$)", "$it$.collect(java.util.stream.Collectors.toList()).get($p$)"));
|
||||
descriptorsMap.put("size", new TypeConversionDescriptor("$it$.size()", "$it$.collect(java.util.stream.Collectors.toList()).size()"));
|
||||
|
||||
descriptorsMap.put("toMap", new TypeConversionDescriptor("$it$.toMap($f$)",
|
||||
"$it$.collect(java.util.stream.Collectors.toMap(java.util.function.Function.identity(), $f$))"));
|
||||
descriptorsMap.put("toList", new TypeConversionDescriptor("$it$.toList()", "$it$.collect(java.util.stream.Collectors.toList())"));
|
||||
descriptorsMap.put("toSet", new TypeConversionDescriptor("$it$.toSet()", "$it$.collect(java.util.stream.Collectors.toSet())"));
|
||||
descriptorsMap.put("toSortedList", new TypeConversionDescriptor("$it$.toSortedList($c$)", "$it$.sorted($c$).collect(java.util.stream.Collectors.toList())"));
|
||||
descriptorsMap.put("toSortedSet", new TypeConversionDescriptor("$it$.toSortedSet($c$)", "$it$.sorted($c$).collect(java.util.stream.Collectors.toSet())"));
|
||||
|
||||
protected TypeConversionDescriptorBase findConversionForMethod(@NotNull PsiType from,
|
||||
@NotNull PsiType to,
|
||||
@NotNull PsiMethod method,
|
||||
String methodName,
|
||||
PsiExpression context,
|
||||
TypeMigrationLabeler labeler) {
|
||||
final TypeConversionDescriptorBase base = DESCRIPTORS_MAP.get(methodName);
|
||||
return base instanceof TypeConversionDescriptor ? ((TypeConversionDescriptor)base).withConversionType(to) : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String ruleFromClass() {
|
||||
return "com.google.common.collect.FluentIterable";
|
||||
return FLUENT_ITERABLE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+3
-1
@@ -29,6 +29,8 @@ import java.util.Map;
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class GuavaFunctionConversionRule extends BaseGuavaTypeConversionRule {
|
||||
public static final String JAVA_UTIL_FUNCTION_FUNCTION = "java.util.function.Function";
|
||||
|
||||
@Override
|
||||
protected void fillSimpleDescriptors(Map<String, TypeConversionDescriptorBase> descriptorsMap) {
|
||||
descriptorsMap.put("apply", new TypeConversionDescriptorBase());
|
||||
@@ -43,6 +45,6 @@ public class GuavaFunctionConversionRule extends BaseGuavaTypeConversionRule {
|
||||
@NotNull
|
||||
@Override
|
||||
public String ruleToClass() {
|
||||
return "java.util.function.Function";
|
||||
return JAVA_UTIL_FUNCTION_FUNCTION;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-3
@@ -27,22 +27,30 @@ import org.jetbrains.annotations.NonNls;
|
||||
public class LambdaParametersTypeConversionDescription extends TypeConversionDescriptor {
|
||||
private static final Logger LOG = Logger.getInstance(LambdaParametersTypeConversionDescription.class);
|
||||
|
||||
public LambdaParametersTypeConversionDescription(@NonNls String stringToReplace, @NonNls String replaceByString, PsiType conversionType) {
|
||||
super(stringToReplace, replaceByString, conversionType);
|
||||
}
|
||||
|
||||
public LambdaParametersTypeConversionDescription(@NonNls String stringToReplace, @NonNls String replaceByString) {
|
||||
super(stringToReplace, replaceByString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiExpression replace(PsiExpression expression) {
|
||||
public final PsiExpression replace(PsiExpression expression) {
|
||||
LOG.assertTrue(expression instanceof PsiMethodCallExpression);
|
||||
PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expression;
|
||||
final PsiExpression[] arguments = methodCall.getArgumentList().getExpressions();
|
||||
if (arguments.length == 1) {
|
||||
final PsiExpression functionArg = arguments[0];
|
||||
convertParameter(functionArg);
|
||||
customizeParameter(convertParameter(functionArg));
|
||||
}
|
||||
return super.replace(expression);
|
||||
}
|
||||
|
||||
protected void customizeParameter(PsiExpression parameter) {
|
||||
|
||||
}
|
||||
|
||||
private static PsiExpression addApplyReference(final PsiExpression expression) {
|
||||
return (PsiExpression)expression.replace(JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(expression.getText() + "::apply", null));
|
||||
}
|
||||
@@ -52,7 +60,7 @@ public class LambdaParametersTypeConversionDescription extends TypeConversionDes
|
||||
final PsiAnonymousClass anonymousClass = ((PsiNewExpression)expression).getAnonymousClass();
|
||||
if (anonymousClass != null) {
|
||||
if (AnonymousCanBeLambdaInspection.canBeConvertedToLambda(anonymousClass, true)) {
|
||||
AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true);
|
||||
AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user