ExtractChainedMapAction: more specific message; Guava FluentIterable support; Collection.forEach test

This commit is contained in:
Tagir Valeev
2017-03-07 13:44:29 +07:00
parent fdfa078e77
commit ed8f4efbef
35 changed files with 104 additions and 41 deletions

View File

@@ -25,7 +25,6 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.chainCall.ChainCallExtractor;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -39,13 +38,6 @@ public class ExtractChainedMapAction extends PsiElementBaseIntentionAction {
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
PsiLocalVariable variable =
PsiTreeUtil.getParentOfType(element, PsiLocalVariable.class, false, PsiStatement.class, PsiLambdaExpression.class);
if (!isApplicable(variable)) return false;
setText(CodeInsightBundle.message("intention.extract.map.step.text", variable.getName()));
return true;
}
@Contract("null -> false")
private static boolean isApplicable(PsiLocalVariable variable) {
if (variable == null || variable.getName() == null) return false;
PsiExpression initializer = variable.getInitializer();
if (initializer == null) return false;
@@ -54,10 +46,16 @@ public class ExtractChainedMapAction extends PsiElementBaseIntentionAction {
PsiCodeBlock block = tryCast(declaration.getParent(), PsiCodeBlock.class);
if (block == null) return false;
PsiLambdaExpression lambda = tryCast(block.getParent(), PsiLambdaExpression.class);
if (ChainCallExtractor.findExtractor(lambda, initializer, variable.getType()) == null) return false;
ChainCallExtractor extractor = ChainCallExtractor.findExtractor(lambda, initializer, variable.getType());
if (extractor == null) return false;
PsiParameter parameter = lambda.getParameterList().getParameters()[0];
return ReferencesSearch.search(parameter).forEach(
(Processor<PsiReference>)ref -> PsiTreeUtil.isAncestor(initializer, ref.getElement(), false));
if (!ReferencesSearch.search(parameter).forEach(
(Processor<PsiReference>)ref -> PsiTreeUtil.isAncestor(initializer, ref.getElement(), false))) {
return false;
}
setText(CodeInsightBundle.message("intention.extract.map.step.text", variable.getName(),
extractor.getMethodName(parameter, initializer, variable.getType())));
return true;
}
@Override

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2000-2017 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.chainCall;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.siyeh.ig.callMatcher.CallMatcher;
import org.jetbrains.annotations.NotNull;
/**
* @author Tagir Valeev
*/
public class GuavaFluentIterableChainCallExtractor implements ChainCallExtractor {
public static final String FLUENT_ITERABLE = "com.google.common.collect.FluentIterable";
private static final CallMatcher NEXT_CALL =
CallMatcher.instanceCall(FLUENT_ITERABLE, "transform", "firstMatch", "transformAndConcat", "anyMatch", "allMatch").parameterCount(1);
@Override
public boolean canExtractChainCall(@NotNull PsiMethodCallExpression call, PsiExpression expression, PsiType expressionType) {
if (expressionType instanceof PsiPrimitiveType) return false;
PsiExpression qualifier = call.getMethodExpression().getQualifierExpression();
if (qualifier == null) return false;
return NEXT_CALL.test(call) ||
("forEach".equals(call.getMethodExpression().getReferenceName()) &&
InheritanceUtil.isInheritor(qualifier.getType(), FLUENT_ITERABLE));
}
@Override
public String getMethodName(PsiVariable variable, PsiExpression expression, PsiType expressionType) {
return "transform";
}
}

View File

@@ -1,4 +1,4 @@
// "Extract variable 'lowerCase' to separate mapping method" "true"
// "Extract variable 'lowerCase' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'arr' to separate mapping method" "true"
// "Extract variable 'arr' to 'mapToObj' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'l' to separate mapping method" "true"
// "Extract variable 'l' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'l' to separate mapping method" "true"
// "Extract variable 'l' to 'asLongStream' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -0,0 +1,8 @@
// "Extract variable 'trimmed' to 'stream().map' operation" "true"
import java.util.Collection;
public class StreamExtract {
void hasNonEmpty(Collection<String> list) {
list.stream().map(String::trim).forEach(trimmed -> System.out.println(trimmed + ":" + trimmed));
}
}

View File

@@ -1,4 +1,4 @@
// "Extract variable 'y' to separate mapping method" "true"
// "Extract variable 'y' to 'mapToInt' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'y' to separate mapping method" "true"
// "Extract variable 'y' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 's' to separate mapping method" "true"
// "Extract variable 's' to 'mapToObj' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'i' to separate mapping method" "true"
// "Extract variable 'i' to 'mapToInt' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'fn' to separate mapping method" "true"
// "Extract variable 'fn' to 'map' operation" "true"
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'set' to separate mapping method" "true"
// "Extract variable 'set' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'y' to separate mapping method" "true"
// "Extract variable 'y' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'l' to separate mapping method" "true"
// "Extract variable 'l' to 'asLongStream' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'lc' to separate mapping method" "true"
// "Extract variable 'lc' to 'thenApply' operation" "true"
import java.util.concurrent.CompletableFuture;
public class Test {

View File

@@ -1,4 +1,4 @@
// "Extract variable 'lowerCase' to separate mapping method" "true"
// "Extract variable 'lowerCase' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'lowerCase' to separate mapping method" "false"
// "Disable 'Extract to separate mapping method'" "false"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'arr' to separate mapping method" "true"
// "Extract variable 'arr' to 'mapToObj' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'l' to separate mapping method" "true"
// "Extract variable 'l' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'l' to separate mapping method" "true"
// "Extract variable 'l' to 'asLongStream' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -0,0 +1,11 @@
// "Extract variable 'trimmed' to 'stream().map' operation" "true"
import java.util.Collection;
public class StreamExtract {
void hasNonEmpty(Collection<String> list) {
list.forEach(s -> {
String <caret>trimmed = s.trim();
System.out.println(trimmed + ":" + trimmed);
});
}
}

View File

@@ -1,4 +1,4 @@
// "Extract variable 'y' to separate mapping method" "true"
// "Extract variable 'y' to 'mapToInt' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'y' to separate mapping method" "false"
// "Disable 'Extract to separate mapping method'" "false"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'y' to separate mapping method" "true"
// "Extract variable 'y' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 's' to separate mapping method" "true"
// "Extract variable 's' to 'mapToObj' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'i' to separate mapping method" "true"
// "Extract variable 'i' to 'mapToInt' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'i' to separate mapping method" "false"
// "Disable 'Extract to separate mapping method'" "false"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'fn' to separate mapping method" "true"
// "Extract variable 'fn' to 'map' operation" "true"
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'set' to separate mapping method" "true"
// "Extract variable 'set' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'y' to separate mapping method" "true"
// "Extract variable 'y' to 'map' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'l' to separate mapping method" "true"
// "Extract variable 'l' to 'asLongStream' operation" "true"
import java.util.*;
import java.util.stream.*;

View File

@@ -1,4 +1,4 @@
// "Extract variable 'lc' to separate mapping method" "true"
// "Extract variable 'lc' to 'thenApply' operation" "true"
import java.util.concurrent.CompletableFuture;
public class Test {

View File

@@ -178,7 +178,7 @@ intention.inline.map.inline.text=Inline ''{0}'' body into the next ''{1}'' call
intention.inline.map.merge.text=Merge ''{0}'' call and ''{1}'' call
intention.inline.map.family=Inline stream mapping method
intention.extract.map.step.family=Extract to separate mapping method
intention.extract.map.step.text=Extract variable ''{0}'' to separate mapping method
intention.extract.map.step.text=Extract variable ''{0}'' to ''{1}'' operation
intention.compose.function.text=Replace nested function call with andThen call
intention.compose.function.family=Replace nested function call with composition
intention.introduce.variable.text=Introduce local variable

View File

@@ -1902,6 +1902,7 @@
<java.refactoring.chainCallExtractor implementation="com.intellij.refactoring.chainCall.StreamChainCallExtractor"/>
<java.refactoring.chainCallExtractor implementation="com.intellij.refactoring.chainCall.CollectionChainCallExtractor"/>
<java.refactoring.chainCallExtractor implementation="com.intellij.refactoring.chainCall.CompletionStageChainCallExtractor"/>
<java.refactoring.chainCallExtractor implementation="com.intellij.refactoring.chainCall.GuavaFluentIterableChainCallExtractor"/>
<diff.lang.DiffIgnoredRangeProvider implementation="com.intellij.diff.lang.JavaDiffIgnoredRangeProvider"/>
</extensions>