StaticPseudoFunctionalStyleMethodInspection: handles filter(list, classAsFilter) and find() with default value

This commit is contained in:
Dmitry Batkovich
2015-04-23 14:59:45 +03:00
parent c53163b34a
commit 36c9328f8d
8 changed files with 108 additions and 29 deletions
@@ -59,9 +59,7 @@ public class AddMethodsDialog extends DialogWrapper {
for (String methodName : StreamApiConstants.STREAM_STREAM_API_METHODS.getValue()) {
model.addElement(methodName);
}
for (String fakeMethodName : StreamApiConstants.FAKE_STREAM_API_METHODS_TO_PATTERN.getValue().keySet()) {
model.addElement(fakeMethodName);
}
model.addElement(StreamApiConstants.FAKE_FIND_MATCHED);
myPatternsCombo.setRenderer(new ColoredListCellRenderer<String>() {
@Override
protected void customizeCellRenderer(JList list, String methodName, int index, boolean selected, boolean hasFocus) {
@@ -70,9 +68,10 @@ public class AddMethodsDialog extends DialogWrapper {
append(methodName + "()", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
}
else {
String pattern = StreamApiConstants.FAKE_STREAM_API_METHODS_TO_PATTERN.getValue().get(methodName);
LOG.assertTrue(pattern != null);
append(String.format(pattern, ""), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
LOG.assertTrue(StreamApiConstants.FAKE_FIND_MATCHED.equals(methodName));
append(String.format(StreamApiConstants.FAKE_FIND_MATCHED_PATTERN, "condition"), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
append(" or ");
append(String.format(StreamApiConstants.FAKE_FIND_MATCHED_WITH_DEFAULT_PATTERN, "condition", "defaultValue"), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
}
}
});
@@ -104,7 +104,7 @@ public class StaticPseudoFunctionalStyleMethodInspection extends BaseJavaBatchLo
if (suitableHandler == null) {
return;
}
final int lambdaIndex = validateMethodParameters(methodCallExpression, method);
final int lambdaIndex = validateMethodParameters(methodCallExpression, method, suitableHandler.getStreamApiMethodName() == StreamApiConstants.FAKE_FIND_MATCHED);
if (lambdaIndex != -1) {
holder.registerProblem(methodCallExpression.getMethodExpression(), "",
new ReplacePseudoLambdaWithLambda(lambdaIndex, methodCallExpression, method, suitableHandler));
@@ -147,26 +147,26 @@ public class StaticPseudoFunctionalStyleMethodInspection extends BaseJavaBatchLo
LOG.assertTrue(expression != null);
final PsiExpression[] expressions = expression.getArgumentList().getExpressions();
PsiExpression lambdaExpression = expressions[myLambdaIndex];
lambdaExpression = convertClassTypeExpression(lambdaExpression);
lambdaExpression = convertToJavaLambda(lambdaExpression, mySuitableHandler.getStreamApiMethodName());
LOG.assertTrue(lambdaExpression != null);
final PsiExpression collectionExpression = expressions[(1 + myLambdaIndex) % 2];
final String pipelineHead = createPipelineHeadText(collectionExpression);
final String patternForFake =
StreamApiConstants.FAKE_STREAM_API_METHODS_TO_PATTERN.getValue().get(mySuitableHandler.getStreamApiMethodName());
final String lambdaExpressionText;
final String elementText;
if (patternForFake == null) {
if (!StreamApiConstants.FAKE_FIND_MATCHED.equals(mySuitableHandler.getStreamApiMethodName())) {
elementText = mySuitableHandler.getStreamApiMethodName();
lambdaExpressionText = lambdaExpression.getText();
}
else {
elementText = String.format(patternForFake, lambdaExpression.getText());
elementText = expressions.length == 3
? String.format(StreamApiConstants.FAKE_FIND_MATCHED_WITH_DEFAULT_PATTERN, lambdaExpression.getText(), expressions[2].getText())
: String.format(StreamApiConstants.FAKE_FIND_MATCHED_PATTERN, lambdaExpression.getText());
lambdaExpressionText = null;
}
final String pipelineTail =
StreamApiConstants.STREAM_STREAM_API_METHODS.getValue().contains(mySuitableHandler.getStreamApiMethodName())
? findSuitableTailMethodForCollection(myMethodPointer.getElement())
@@ -177,11 +177,24 @@ public class StaticPseudoFunctionalStyleMethodInspection extends BaseJavaBatchLo
JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced.getParent());
}
@NotNull
private static PsiExpression convertClassTypeExpression(PsiExpression expression) {
final PsiType type = expression.getType();
if (type instanceof PsiClassType) {
final PsiClass resolvedClass = ((PsiClassType)type).resolve();
if (resolvedClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(resolvedClass.getQualifiedName())) {
return JavaPsiFacade.getElementFactory(expression.getProject())
.createExpressionFromText("(" + expression.getText() + ")::isInstance", null);
}
}
return expression;
}
private static String createPipelineHeadText(PsiExpression collectionExpression) {
final PsiType type = collectionExpression.getType();
if (type instanceof PsiClassType) {
final PsiClass resolved = ((PsiClassType)type).resolve();
LOG.assertTrue(resolved != null && resolved.getQualifiedName() != null);
LOG.assertTrue(resolved != null && resolved.getQualifiedName() != null, type);
return collectionExpression.getText() + ".stream()";
}
else if (type instanceof PsiArrayType) {
@@ -207,17 +220,22 @@ public class StaticPseudoFunctionalStyleMethodInspection extends BaseJavaBatchLo
}
}
private static int validateMethodParameters(final PsiMethodCallExpression methodCallExpression, final PsiMethod method) {
private static int validateMethodParameters(final PsiMethodCallExpression methodCallExpression, final PsiMethod method, boolean canThirdParameterExist) {
final PsiType[] argumentTypes = methodCallExpression.getArgumentList().getExpressionTypes();
final PsiParameter[] expectedParameters = method.getParameterList().getParameters();
if (argumentTypes.length != expectedParameters.length || expectedParameters.length != 2) {
if (argumentTypes.length != expectedParameters.length) {
return -1;
}
final int collectionOrArrayIndex = findCollectionOrArrayPlacement(expectedParameters);
if (collectionOrArrayIndex == -1) {
return -1;
if (expectedParameters.length == 2 || (canThirdParameterExist && expectedParameters.length == 3)) {
final int collectionOrArrayIndex = findCollectionOrArrayPlacement(expectedParameters);
if (collectionOrArrayIndex == -1) {
return -1;
}
return (1 + collectionOrArrayIndex) % 2;
}
return (1 + collectionOrArrayIndex) % 2;
return -1;
}
private static int findCollectionOrArrayPlacement(final PsiParameter[] parameters) {
@@ -232,6 +250,12 @@ public class StaticPseudoFunctionalStyleMethodInspection extends BaseJavaBatchLo
}
private static PsiExpression convertToJavaLambda(PsiExpression expression, String streamApiMethodName) {
if (streamApiMethodName.equals(StreamApiConstants.FAKE_FIND_MATCHED)) {
streamApiMethodName = StreamApiConstants.FILTER;
}
if (expression instanceof PsiMethodReferenceExpression) {
return expression;
}
if (expression instanceof PsiLambdaExpression) {
return expression;
}
@@ -40,6 +40,7 @@ public interface StreamApiConstants {
String FAKE_FIND_MATCHED = "#findMatched";
String FAKE_FIND_MATCHED_PATTERN = "filter(%s).findFirst().get()";
String FAKE_FIND_MATCHED_WITH_DEFAULT_PATTERN = "filter(%s).findFirst().orElseGet(() -> %s)";
String JAVA_UTIL_STREAM_COLLECTORS = "java.util.stream.Collectors";
@@ -51,16 +52,6 @@ public interface StreamApiConstants {
}
};
SoftLazyValue<Map<String, String>> FAKE_STREAM_API_METHODS_TO_PATTERN = new SoftLazyValue<Map<String, String>>() {
@NotNull
@Override
protected Map<String, String> compute() {
final HashMap<String, String> map = new HashMap<String, String>();
map.put(FAKE_FIND_MATCHED, FAKE_FIND_MATCHED_PATTERN);
return map;
}
};
String SKIP = "skip";
String TO_ARRAY = "toArray";
}
@@ -0,0 +1,14 @@
import com.google.common.collect.Iterables;
import com.google.common.base.Predicate;
import java.lang.String;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
class c {
void m() {
List<String> l = new ArrayList<String>();
Iterables.filt<caret>er(l, String.class);
}
}
@@ -0,0 +1,15 @@
import com.google.common.collect.Iterables;
import com.google.common.base.Predicate;
import java.lang.String;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.util.stream.Collectors;
class c {
void m() {
List<String> l = new ArrayList<String>();
l.stream().filter((String.class)::isInstance).collect(Collectors.toList());
}
}
@@ -0,0 +1,14 @@
import com.google.common.collect.Iterables;
import com.google.common.base.Predicate;
import java.lang.String;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
class c {
void m() {
List<String> l = new ArrayList<String>();
Iterables.fin<caret>d(l, String::isEmpty, "asd");
}
}
@@ -0,0 +1,14 @@
import com.google.common.collect.Iterables;
import com.google.common.base.Predicate;
import java.lang.String;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
class c {
void m() {
List<String> l = new ArrayList<String>();
l.stream().filter(String::isEmpty).findFirst().orElseGet(() -> "asd");
}
}
@@ -83,6 +83,14 @@ public class StaticPseudoFunctionalStyleMethodTest extends JavaCodeInsightFixtur
doTest();
}
public void testFindWithDefaultValue() {
doTest();
}
public void testFilterWithInstanceOf() {
doTest();
}
public void _testReplaceWithMethodReference() {
doTest();
}