From 278ceaca882b6d351ce9523dc640cb1a470e6d60 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Wed, 21 Dec 2016 13:24:01 +0300 Subject: [PATCH] guava type migration: fix for filter(Class) migration (should add cast to new type) IDEA-165420 --- .../guava/FluentIterableConversionUtil.java | 39 ++++++++++++++----- .../GuavaFluentIterableConversionRule.java | 2 +- .../guava/filterIsInstance_after.java | 2 +- .../fluentIterableAndOptional_after.java | 2 +- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/FluentIterableConversionUtil.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/FluentIterableConversionUtil.java index fcf76f30c496..2cc9126a2bb5 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/FluentIterableConversionUtil.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/FluentIterableConversionUtil.java @@ -112,9 +112,8 @@ public class FluentIterableConversionUtil { } @Nullable - static TypeConversionDescriptor getFilterDescriptor(PsiMethod method) { + static TypeConversionDescriptor getFilterDescriptor(@NotNull PsiMethod method, @Nullable PsiExpression context) { LOG.assertTrue("filter".equals(method.getName())); - final PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameters.length != 1) return null; final PsiParameter parameter = parameters[0]; @@ -123,7 +122,22 @@ public class FluentIterableConversionUtil { final PsiClass resolvedClass = ((PsiClassType)type).resolve(); if (resolvedClass == null) return null; if (CommonClassNames.JAVA_LANG_CLASS.equals(resolvedClass.getQualifiedName())) { - return new GuavaFilterInstanceOfConversionDescriptor(); + if (context == null) return null; + PsiMethodCallExpression methodCall = null; + if (context instanceof PsiMethodCallExpression) { + methodCall = (PsiMethodCallExpression)context; + } + else if (context.getParent() instanceof PsiMethodCallExpression) { + methodCall = (PsiMethodCallExpression)context.getParent(); + } + if (methodCall == null) return null; + final PsiType filteredType = methodCall.getType(); + if (!(filteredType instanceof PsiClassType)) return null; + final PsiType[] filterParameters = ((PsiClassType)filteredType).getParameters(); + if (filterParameters.length != 1) return null; + final String filterClassName = getFilterClassText(filterParameters[0]); + if (filterClassName == null) return null; + return new GuavaFilterInstanceOfConversionDescriptor(filterClassName); } else if (GuavaLambda.PREDICATE.getClassQName().equals(resolvedClass.getQualifiedName())) { return new GuavaTypeConversionDescriptor("$it$.filter($p$)", "$it$." + StreamApiConstants.FILTER + "($p$)"); @@ -131,6 +145,17 @@ public class FluentIterableConversionUtil { return null; } + @Nullable + private static String getFilterClassText(PsiType type) { + final PsiClass filterClass = PsiUtil.resolveClassInType(type); + if (filterClass != null) return filterClass.getQualifiedName(); + if (type instanceof PsiCapturedWildcardType) { + final PsiClass boundClass = PsiUtil.resolveClassInType(((PsiCapturedWildcardType)type).getUpperBound()); + if (boundClass != null) return boundClass.getQualifiedName(); + } + return null; + } + static class TransformAndConcatConversionRule extends GuavaTypeConversionDescriptor { public TransformAndConcatConversionRule() { super("$q$.transformAndConcat($params$)", "$q$.flatMap($params$)"); @@ -230,16 +255,12 @@ public class FluentIterableConversionUtil { } private static class GuavaFilterInstanceOfConversionDescriptor extends TypeConversionDescriptor { - public GuavaFilterInstanceOfConversionDescriptor() { - super("$it$.filter($p$)", "$it$." + StreamApiConstants.FILTER + "($p$)"); + public GuavaFilterInstanceOfConversionDescriptor(String filterClassQName) { + super("$it$.filter($p$)", "$it$." + StreamApiConstants.FILTER + "(" + filterClassQName + ".class::isInstance)." + StreamApiConstants.MAP + "(" + filterClassQName + ".class::cast)"); } @Override public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) { - final PsiExpression argument = ((PsiMethodCallExpression)expression).getArgumentList().getExpressions()[0]; - final PsiExpression newArgument = JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText("(" + argument.getText() + ")::isInstance", argument); - ParenthesesUtils.removeParentheses((PsiExpression)((PsiMethodReferenceExpression)newArgument).getQualifier(), false); - argument.replace(newArgument); return super.replace(expression, evaluator); } } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java index 8bb129493d46..9f3345158f0e 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java @@ -158,7 +158,7 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu } }; } else if (methodName.equals("filter")) { - descriptorBase = FluentIterableConversionUtil.getFilterDescriptor(method); + descriptorBase = FluentIterableConversionUtil.getFilterDescriptor(method, context); } else if (methodName.equals("isEmpty")) { descriptorBase = new TypeConversionDescriptor("$q$.isEmpty()", null) { @Override diff --git a/java/typeMigration/testData/inspections/guava/filterIsInstance_after.java b/java/typeMigration/testData/inspections/guava/filterIsInstance_after.java index 218991616cb3..15be466c9fc3 100644 --- a/java/typeMigration/testData/inspections/guava/filterIsInstance_after.java +++ b/java/typeMigration/testData/inspections/guava/filterIsInstance_after.java @@ -6,6 +6,6 @@ class A { ArrayList strings = new ArrayList(); Stream it = strings.stream(); - int i = (int) it.filter(String::isEmpty).filter(String.class::isInstance).count(); + int i = (int) it.filter(String::isEmpty).filter(String.class::isInstance).map(String.class::cast).count(); } } \ No newline at end of file diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional_after.java b/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional_after.java index d717ca06ec09..530fbe49c3a6 100644 --- a/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional_after.java +++ b/java/typeMigration/testData/inspections/guava/fluentIterableAndOptional_after.java @@ -15,7 +15,7 @@ public class Main18 { class B { Stream getFIterable() { - return new ArrayList().stream().filter(String.class::isInstance); + return new ArrayList().stream().filter(String.class::isInstance).map(String.class::cast); } }