IDEA-200455 Suggest to replace (a, b) -> a + b lambdas with Integer::sum, Long::sum, Double::sum

This commit is contained in:
Tagir Valeev
2019-01-31 14:20:20 +07:00
parent cde7d6a7ff
commit 8da8dca8e0
14 changed files with 95 additions and 13 deletions

View File

@@ -166,7 +166,7 @@
</component>
<component id="551b5" class="javax.swing.JLabel">
<constraints>
<grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Test class:"/>
@@ -190,7 +190,7 @@
</component>
<component id="49afe" class="javax.swing.JLabel">
<constraints>
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Subclass:"/>
@@ -322,7 +322,7 @@
<border type="none"/>
<children/>
</grid>
<grid id="322e3" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="322e3" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -354,6 +354,14 @@
<text value="Replace null-check with Objects::nonNull or Objects::isNull"/>
</properties>
</component>
<component id="de0d0" class="com.intellij.ui.components.JBCheckBox" binding="myReplaceSumCb">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Use Integer::sum, etc. when possible"/>
</properties>
</component>
</children>
</grid>
</children>

View File

@@ -72,12 +72,13 @@ public class CodeStyleGenerationConfigurable implements CodeStyleConfigurable {
private JTextField myTestClassSuffix;
private JTextField mySubclassPrefix;
private JTextField mySubclassSuffix;
private JBCheckBox myReplaceSumCb;
private CommenterForm myCommenterForm;
private SortedListModel<String> myRepeatAnnotationsModel;
public CodeStyleGenerationConfigurable(CodeStyleSettings settings) {
mySettings = settings;
myPanel.setBorder(JBUI.Borders.empty(2, 2, 2, 2));
myPanel.setBorder(JBUI.Borders.empty(2));
myJavaVisibilityPanel = new JavaVisibilityPanel(false, true, RefactoringBundle.message("default.visibility.border.title"));
}
@@ -133,6 +134,7 @@ public class CodeStyleGenerationConfigurable implements CodeStyleConfigurable {
myReplaceInstanceOfCb.setSelected(javaSettings.REPLACE_INSTANCEOF_AND_CAST);
myReplaceNullCheckCb.setSelected(javaSettings.REPLACE_NULL_CHECK);
myReplaceSumCb.setSelected(javaSettings.REPLACE_SUM);
myRepeatAnnotationsModel.clear();
myRepeatAnnotationsModel.addAll(javaSettings.getRepeatAnnotations());
@@ -174,6 +176,7 @@ public class CodeStyleGenerationConfigurable implements CodeStyleConfigurable {
javaSettings.REPLACE_INSTANCEOF_AND_CAST = myReplaceInstanceOfCb.isSelected();
javaSettings.REPLACE_NULL_CHECK = myReplaceNullCheckCb.isSelected();
javaSettings.REPLACE_SUM = myReplaceSumCb.isSelected();
myCommenterForm.apply(settings);
@@ -225,6 +228,7 @@ public class CodeStyleGenerationConfigurable implements CodeStyleConfigurable {
isModified |= isModified(myReplaceInstanceOfCb, javaSettings.REPLACE_INSTANCEOF_AND_CAST);
isModified |= isModified(myReplaceNullCheckCb, javaSettings.REPLACE_NULL_CHECK);
isModified |= isModified(myReplaceSumCb, javaSettings.REPLACE_SUM);
isModified |= !javaSettings.VISIBILITY.equals(myJavaVisibilityPanel.getVisibility());

View File

@@ -106,6 +106,7 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im
public boolean REPLACE_CAST = false;
public boolean REPLACE_INSTANCEOF_AND_CAST = false;
public boolean REPLACE_NULL_CHECK = true;
public boolean REPLACE_SUM = true;
public boolean SPACES_WITHIN_ANGLE_BRACKETS;

View File

@@ -0,0 +1,8 @@
// "Replace lambda with method reference" "true"
import java.util.function.IntBinaryOperator;
class Bar {
public void test(Object obj) {
IntBinaryOperator op = Integer::sum;
}
}

View File

@@ -0,0 +1,10 @@
// "Replace lambda with method reference" "true"
class Bar {
interface Foo {
int sum(Byte b1, Byte b2);
}
public void test(Object obj) {
Foo foo = Integer::sum;
}
}

View File

@@ -0,0 +1,8 @@
// "Replace lambda with method reference" "true"
import java.util.function.LongBinaryOperator;
class Bar {
public void test(Object obj) {
LongBinaryOperator op = Long::sum;
}
}

View File

@@ -0,0 +1,8 @@
// "Replace lambda with method reference" "true"
import java.util.function.IntBinaryOperator;
class Bar {
public void test(Object obj) {
IntBinaryOperator op = (a, b) -> (a) + <caret>b;
}
}

View File

@@ -0,0 +1,10 @@
// "Replace lambda with method reference" "true"
class Bar {
interface Foo {
int sum(Byte b1, Byte b2);
}
public void test(Object obj) {
Foo foo = (b1, b2) -> b1<caret> + b2;
}
}

View File

@@ -0,0 +1,8 @@
// "Replace lambda with method reference" "true"
import java.util.function.LongBinaryOperator;
class Bar {
public void test(Object obj) {
LongBinaryOperator op = (a, b) -> b + <caret>a;
}
}

View File

@@ -7,7 +7,7 @@ import java.util.stream.Collectors;
public class Main {
private Map<String, Integer> test(String... list) {
Map<String, Integer> map = Arrays.stream(list).filter(Objects::nonNull).collect(Collectors.toMap(s -> s, s -> 1, (a, b) -> a + b));
Map<String, Integer> map = Arrays.stream(list).filter(Objects::nonNull).collect(Collectors.toMap(s -> s, s -> 1, Integer::sum));
return map;
}

View File

@@ -3,6 +3,6 @@ import java.util.Map;
public class Main {
public void testMerge(Map<String, Integer> map, String key) {
map.merge(key, 1, (a, b) -> a + b)
map.merge(key, 1, Integer::sum)
}
}

View File

@@ -3,6 +3,6 @@ import java.util.Map;
public class Main {
public void testMerge(Map<String, Integer> map, String key) {
map.merge(key, 1, (a, b) -> b + a)
map.merge(key, 1, Integer::sum)
}
}

View File

@@ -4,7 +4,7 @@ import java.util.Map;
public class Main {
public void testMerge(Map<String, Integer> map, String key, int add) {
Integer val = map.get(key);
map.merge(key, add, (a, b) -> b + a)
map.merge(key, add, Integer::sum)
System.out.println(val);
}
}

View File

@@ -272,11 +272,15 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI
return new MethodReferenceCandidate(expression, true, javaSettings.REPLACE_INSTANCEOF_AND_CAST);
}
else if (expression instanceof PsiBinaryExpression) {
PsiExpression comparedWithNull =
PsiUtil.skipParenthesizedExprDown(ExpressionUtils.getValueComparedWithNull((PsiBinaryExpression)expression));
PsiBinaryExpression binOp = (PsiBinaryExpression)expression;
PsiExpression comparedWithNull = PsiUtil.skipParenthesizedExprDown(ExpressionUtils.getValueComparedWithNull(binOp));
if (isMethodReferenceArgCandidate(comparedWithNull)) {
return new MethodReferenceCandidate(expression, true, javaSettings.REPLACE_NULL_CHECK);
}
if (binOp.getOperationTokenType().equals(JavaTokenType.PLUS) &&
isMethodReferenceArgCandidate(binOp.getLOperand()) && isMethodReferenceArgCandidate(binOp.getROperand())) {
return new MethodReferenceCandidate(expression, true, javaSettings.REPLACE_SUM);
}
}
else if (expression instanceof PsiTypeCastExpression) {
if (!isMethodReferenceArgCandidate(((PsiTypeCastExpression)expression).getOperand())) return null;
@@ -413,16 +417,29 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI
}
}
else if (element instanceof PsiBinaryExpression) {
PsiBinaryExpression nullCheck = (PsiBinaryExpression)element;
PsiExpression operand = ExpressionUtils.getValueComparedWithNull(nullCheck);
PsiBinaryExpression binOp = (PsiBinaryExpression)element;
PsiExpression operand = ExpressionUtils.getValueComparedWithNull(binOp);
if(operand != null && isSoleParameter(parameters, operand)) {
IElementType tokenType = nullCheck.getOperationTokenType();
IElementType tokenType = binOp.getOperationTokenType();
if(JavaTokenType.EQEQ.equals(tokenType)) {
return "java.util.Objects::isNull";
} else if(JavaTokenType.NE.equals(tokenType)) {
return "java.util.Objects::nonNull";
}
}
if(binOp.getOperationTokenType().equals(JavaTokenType.PLUS)) {
PsiExpression left = binOp.getLOperand();
PsiExpression right = binOp.getROperand();
if (parameters.length == 2 &&
((ExpressionUtils.isReferenceTo(left, parameters[0]) && ExpressionUtils.isReferenceTo(right, parameters[1])) ||
(ExpressionUtils.isReferenceTo(left, parameters[1]) && ExpressionUtils.isReferenceTo(right, parameters[0])))) {
PsiType type = binOp.getType();
if (type instanceof PsiPrimitiveType && TypeConversionUtil.isNumericType(type)) {
// Can be only int/long/double/float as short/byte/char would be promoted to int
return ((PsiPrimitiveType)type).getBoxedTypeName() + "::sum";
}
}
}
}
else if (element instanceof PsiTypeCastExpression) {
PsiTypeCastExpression castExpression = (PsiTypeCastExpression)element;