guava type migration: tests work now + fixed chained migration

This commit is contained in:
Dmitry Batkovich
2015-10-01 18:26:30 +03:00
parent 200603f1f3
commit 64aecca3dc
9 changed files with 144 additions and 30 deletions
@@ -384,6 +384,8 @@ public class TypeMigrationLabeler {
return false;
}
type = JavaPsiFacade.getElementFactory(element.getProject()).createTypeFromText(type.getCanonicalText(), element);
if (resolved instanceof PsiMethod) {
final PsiMethod method = ((PsiMethod)resolved);
final PsiMethod[] methods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY);
@@ -39,7 +39,7 @@ public class TypeConversionDescriptor extends TypeConversionDescriptorBase {
myExpression = expression;
}
public TypeConversionDescriptor(String stringToReplace, String replaceByString, PsiType conversionType) {
public TypeConversionDescriptor(@NonNls final String stringToReplace, @NonNls final String replaceByString, PsiType conversionType) {
this(stringToReplace, replaceByString);
myConversionType = conversionType;
}
@@ -21,6 +21,7 @@ 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.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,38 +31,69 @@ import java.util.Map;
* @author Dmitry Batkovich
*/
public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRule {
private static final Map<String, TypeConversionDescriptorBase> DESCRIPTORS_MAP = new HashMap<String, TypeConversionDescriptorBase>();
private static final Map<String, TypeConversionDescriptorFactory> DESCRIPTORS_MAP =
new HashMap<String, TypeConversionDescriptorFactory>();
public static final String FLUENT_ITERABLE = "com.google.common.collect.FluentIterable";
private static class TypeConversionDescriptorFactory {
private final String myStringToReplace;
private final String myReplaceByString;
private final boolean myWithLambdaParameter;
private final boolean myChainedMethod;
public TypeConversionDescriptorFactory(String stringToReplace, String replaceByString, boolean withLambdaParameter) {
this(stringToReplace, replaceByString, withLambdaParameter, false);
}
public TypeConversionDescriptorFactory(@NonNls final String stringToReplace,
@NonNls final String replaceByString,
boolean withLambdaParameter,
boolean chainedMethod) {
myStringToReplace = stringToReplace;
myReplaceByString = replaceByString;
myWithLambdaParameter = withLambdaParameter;
myChainedMethod = chainedMethod;
}
public TypeConversionDescriptor create() {
return myWithLambdaParameter ? new LambdaParametersTypeConversionDescription(myStringToReplace, myReplaceByString)
: new TypeConversionDescriptor(myStringToReplace, myReplaceByString);
}
public boolean isChainedMethod() {
return myChainedMethod;
}
}
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$)"));
new TypeConversionDescriptorFactory("$it$.contains($o$)", "$it$.anyMatch(e -> e != null && e.equals($o$))", false));
DESCRIPTORS_MAP.put("from", new TypeConversionDescriptorFactory("FluentIterable.from($it$)", "$it$.stream()", false, true));
DESCRIPTORS_MAP.put("isEmpty", new TypeConversionDescriptorFactory("$q$.isEmpty()", "$q$.findAny().isPresent()", false));
DESCRIPTORS_MAP.put("skip", new TypeConversionDescriptorFactory("$q$.skip($p$)", "$q$.skip($p$)", false, true));
DESCRIPTORS_MAP.put("limit", new TypeConversionDescriptorFactory("$q$.limit($p$)", "$q$.limit($p$)", false, true));
DESCRIPTORS_MAP.put("first", new TypeConversionDescriptorFactory("$q$.first()", "$q$.findFirst()", false));
DESCRIPTORS_MAP.put("transform", new TypeConversionDescriptorFactory("$q$.transform($params$)", "$q$.map($params$)", true, true));
//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$)"));
DESCRIPTORS_MAP.put("allMatch", new TypeConversionDescriptorFactory("$it$.allMatch($c$)", "$it$." + StreamApiConstants.ALL_MATCH + "($c$)", true));
DESCRIPTORS_MAP.put("anyMatch", new TypeConversionDescriptorFactory("$it$.anyMatch($c$)", "$it$." + StreamApiConstants.ANY_MATCH + "($c$)", true));
//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("filter", new TypeConversionDescriptorFactory("$it$.filter($p$)", "$it$." + StreamApiConstants.FILTER + "($p$)", true, true));
DESCRIPTORS_MAP.put("first", new TypeConversionDescriptorFactory("$it$.first()", "$it$." + StreamApiConstants.FIND_FIRST + "()", false));
DESCRIPTORS_MAP.put("firstMatch", new TypeConversionDescriptorFactory("$it$.firstMatch($p$)", "$it$.filter($p$).findFirst()", true));
DESCRIPTORS_MAP.put("get", new TypeConversionDescriptorFactory("$it$.get($p$)", "$it$.collect(java.util.stream.Collectors.toList()).get($p$)", false));
DESCRIPTORS_MAP.put("size", new TypeConversionDescriptorFactory("$it$.size()", "$it$.collect(java.util.stream.Collectors.toList()).size()", false));
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())"));
DESCRIPTORS_MAP.put("toMap", new TypeConversionDescriptorFactory("$it$.toMap($f$)",
"$it$.collect(java.util.stream.Collectors.toMap(java.util.function.Function.identity(), $f$))", false));
DESCRIPTORS_MAP.put("toList", new TypeConversionDescriptorFactory("$it$.toList()", "$it$.collect(java.util.stream.Collectors.toList())", false));
DESCRIPTORS_MAP.put("toSet", new TypeConversionDescriptorFactory("$it$.toSet()", "$it$.collect(java.util.stream.Collectors.toSet())", false));
DESCRIPTORS_MAP.put("toSortedList", new TypeConversionDescriptorFactory("$it$.toSortedList($c$)", "$it$.sorted($c$).collect(java.util.stream.Collectors.toList())", false));
DESCRIPTORS_MAP.put("toSortedSet", new TypeConversionDescriptorFactory("$it$.toSortedSet($c$)", "$it$.sorted($c$).collect(java.util.stream.Collectors.toSet())", false));
}
@@ -73,8 +105,17 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu
String methodName,
PsiExpression context,
TypeMigrationLabeler labeler) {
final TypeConversionDescriptorBase base = DESCRIPTORS_MAP.get(methodName);
return base instanceof TypeConversionDescriptor ? ((TypeConversionDescriptor)base).withConversionType(to) : null;
final TypeConversionDescriptorFactory base = DESCRIPTORS_MAP.get(methodName);
if (base != null) {
final TypeConversionDescriptor descriptor = base.create();
if (base.isChainedMethod()) {
descriptor.withConversionType(to);
}
return descriptor;
}
else {
return null;
}
}
@NotNull
@@ -47,15 +47,27 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase {
moduleBuilder.addJdk(IdeaTestUtil.getMockJdk18Path().getPath());
}
public void _testOptional() {
public void testOptional() {
doTest();
}
public void _testOptional2() {
public void testOptional2() {
doTest();
}
public void _testSimpleFluentIterable() {
public void testSimpleFluentIterable() {
doTest();
}
public void testChainedFluentIterable() {
doTest();
}
public void _testFluentIterableChainWithoutVariable() {
doTest();
}
public void _testChainedFluentIterableWithChainedInitializer() {
doTest();
}
@@ -0,0 +1,27 @@
import com.google.common.base.Predicate;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import java.util.ArrayList;
import java.util.List;
class A {
void c() {
ArrayList<String> strings = new ArrayList<String>();
FluentIterable<String> i<caret>t = FluentIterable.from(strings);
List<Boolean> booleans = it.transform(String::isEmpty).toList();
boolean empty = it.transform(s -> s.trim()).transform(new Function<String, char[]>() {
@Override
public char[] apply(String input) {
return input.toCharArray();
}
}).skip(777).filter(new Predicate<char[]>() {
@Override
public boolean apply(char[] input) {
return input.length != 10;
}
}).isEmpty();
}
}
@@ -0,0 +1,15 @@
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class A {
void c() {
ArrayList<String> strings = new ArrayList<String>();
Stream<String> it = strings.stream();
List<Boolean> booleans = it.map(String::isEmpty).collect(Collectors.toList());
boolean empty = it.map(s -> s.trim()).map(input -> input.toCharArray()).skip(777).filter(input -> input.length != 10).findAny().isPresent();
}
}
@@ -0,0 +1,17 @@
import java.util.Optional;
class A {
java.util.Optional<String> m1() {
Optional<String> o = Optional.empty();
String s = o.get();
return o;
}
void w1() {
java.util.Optional<String> someVar = m1();
System.out.println(someVar.get());
System.out.println(someVar.isPresent() ? Collections.singleton(someVar.get()) : Collections.emptySet());
}
}
@@ -15,7 +15,7 @@ class A {
List<String> main(String[] args) {
ArrayList<String> strings = new ArrayList<String>();
FluentIterable<String> it = FluentIterable.from(strings);
FluentIterable<String> i<caret>t = FluentIterable.from(strings);
it = it.transform(input -> input.intern());
it = it.transform(String::trim);
it = it.transform(new Function<String, String>() {
@@ -20,8 +20,8 @@ class A {
it = it.map(input -> input.intern());
it = it.map(String::trim);
it = it.map(input -> {
System.out.println("do some action on " + input);
return input.substring(0, 10);
System.out.println("do some action on " + input);
return input.substring(0, 10);
});
it = it.map(myFunction::apply);
return it.collect(Collectors.toList());