mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
Inspection: Expression can be folded into Stream chain (IDEA-187123)
This commit is contained in:
@@ -758,6 +758,11 @@
|
||||
enabledByDefault="true" level="WARNING"
|
||||
key="inspection.redundant.comparator.comparing.display.name" bundle="messages.InspectionsBundle"
|
||||
implementationClass="com.intellij.codeInspection.RedundantComparatorComparingInspection"/>
|
||||
<localInspection groupPath="Java,Java language level migration aids" language="JAVA" shortName="FoldExpressionIntoStream"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.language.level.specific.issues.and.migration.aids8"
|
||||
enabledByDefault="true" level="INFORMATION"
|
||||
key="inspection.fold.expression.into.stream.display.name" bundle="messages.InspectionsBundle"
|
||||
implementationClass="com.intellij.codeInspection.streamMigration.FoldExpressionIntoStreamInspection"/>
|
||||
<globalInspection groupPath="Java" language="JAVA" shortName="EmptyMethod" displayName="Empty method" groupKey="group.names.declaration.redundancy" enabledByDefault="true" groupBundle="messages.InspectionsBundle"
|
||||
level="WARNING" implementationClass="com.intellij.codeInspection.emptyMethod.EmptyMethodInspection"/>
|
||||
<globalInspection groupPath="Java" language="JAVA" shortName="UnusedReturnValue" bundle="messages.InspectionsBundle" key="inspection.unused.return.value.display.name"
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInspection.streamMigration;
|
||||
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.util.LambdaGenerationUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import com.intellij.psi.impl.PsiDiamondTypeUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.ig.psiutils.*;
|
||||
import one.util.streamex.IntStreamEx;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.intellij.codeInsight.intention.impl.StreamRefactoringUtil.getMapOperationName;
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
|
||||
public class FoldExpressionIntoStreamInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
if (!PsiUtil.isLanguageLevel8OrHigher(holder.getFile())) {
|
||||
return PsiElementVisitor.EMPTY_VISITOR;
|
||||
}
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitPolyadicExpression(PsiPolyadicExpression expression) {
|
||||
TerminalGenerator generator = getGenerator(expression);
|
||||
if (generator == null) return;
|
||||
if (extractDiff(generator, expression).isEmpty()) return;
|
||||
if (!LambdaGenerationUtil.canBeUncheckedLambda(expression)) return;
|
||||
holder.registerProblem(expression, InspectionsBundle.message("inspection.fold.expression.into.stream.display.name"), new FoldExpressionIntoStreamFix());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static List<PsiExpression> extractDiff(TerminalGenerator generator,
|
||||
PsiPolyadicExpression expression) {
|
||||
EquivalenceChecker equivalence = EquivalenceChecker.getCanonicalPsiEquivalence();
|
||||
PsiExpression[] operands = generator.getOperands(expression);
|
||||
if (operands.length < 3) return Collections.emptyList();
|
||||
List<PsiExpression> elements = new ArrayList<>();
|
||||
for (int i = 1; i < operands.length; i++) {
|
||||
if (!Objects.equals(operands[0].getType(), operands[i].getType())) return Collections.emptyList();
|
||||
EquivalenceChecker.Match match = equivalence.expressionsMatch(operands[0], operands[i]);
|
||||
if (!match.isPartialMatch()) return Collections.emptyList();
|
||||
PsiExpression left = tryCast(match.getLeftDiff(), PsiExpression.class);
|
||||
PsiExpression right = tryCast(match.getRightDiff(), PsiExpression.class);
|
||||
if (left == null || right == null) return Collections.emptyList();
|
||||
if (elements.isEmpty()) {
|
||||
if (!StreamApiUtil.isSupportedStreamElement(left.getType()) || !ExpressionUtils.isSafelyRecomputableExpression(left)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (operands[0] instanceof PsiBinaryExpression) {
|
||||
PsiBinaryExpression binOp = (PsiBinaryExpression)operands[0];
|
||||
if (ComparisonUtils.isComparison(binOp) &&
|
||||
(left == binOp.getLOperand() && ExpressionUtils.isSafelyRecomputableExpression(binOp.getROperand())) ||
|
||||
(left == binOp.getROperand() && ExpressionUtils.isSafelyRecomputableExpression(binOp.getLOperand()))) {
|
||||
// Disable for simple comparison chains like "a == null && b == null && c == null":
|
||||
// using Stream API here looks an overkill
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
elements.add(left);
|
||||
}
|
||||
else if (elements.get(0) != left) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (!Objects.equals(left.getType(), right.getType()) ||
|
||||
!ExpressionUtils.isSafelyRecomputableExpression(right)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
elements.add(right);
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
private interface TerminalGenerator {
|
||||
default PsiExpression[] getOperands(PsiPolyadicExpression polyadicExpression) {
|
||||
return polyadicExpression.getOperands();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
String generateTerminal(PsiType elementType, String lambda, CommentTracker ct);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TerminalGenerator getGenerator(PsiPolyadicExpression polyadicExpression) {
|
||||
IElementType tokenType = polyadicExpression.getOperationTokenType();
|
||||
if (tokenType.equals(JavaTokenType.OROR)) {
|
||||
return (elementType, lambda, ct) -> ".anyMatch(" + lambda + ")";
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.ANDAND)) {
|
||||
return (elementType, lambda, ct) -> ".allMatch(" + lambda + ")";
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.PLUS)) {
|
||||
PsiType type = polyadicExpression.getType();
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
if (!StreamApiUtil.isSupportedStreamElement(type)) return null;
|
||||
return (elementType, lambda, ct) -> "." + getMapOperationName(elementType, type) + "(" + lambda + ").sum()";
|
||||
}
|
||||
if (!TypeUtils.isJavaLangString(type)) return null;
|
||||
PsiExpression[] operands = polyadicExpression.getOperands();
|
||||
String mapToString;
|
||||
PsiType operandType = operands[0].getType();
|
||||
if (!InheritanceUtil.isInheritor(operandType, "java.lang.CharSequence")) {
|
||||
if (!StreamApiUtil.isSupportedStreamElement(operandType)) return null;
|
||||
mapToString = "."+getMapOperationName(operandType, type)+"(String::valueOf)";
|
||||
} else {
|
||||
mapToString = "";
|
||||
}
|
||||
if (operands.length > 4 && operands.length % 2 == 1 && ExpressionUtils.isSafelyRecomputableExpression(operands[1]) &&
|
||||
IntStreamEx.range(1, operands.length, 2).elements(operands).pairMap(PsiEquivalenceUtil::areElementsEquivalent)
|
||||
.allMatch(Boolean.TRUE::equals)) {
|
||||
PsiExpression delimiter = operands[1];
|
||||
return new TerminalGenerator() {
|
||||
@Override
|
||||
public PsiExpression[] getOperands(PsiPolyadicExpression polyadicExpression) {
|
||||
PsiExpression[] ops = polyadicExpression.getOperands();
|
||||
return IntStreamEx.range(0, ops.length, 2).elements(ops).toArray(PsiExpression.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String generateTerminal(PsiType elementType, String lambda, CommentTracker ct) {
|
||||
return mapToString(elementType, operandType, lambda) + mapToString +
|
||||
".collect(" + CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS + ".joining(" + ct.text(delimiter) + "))";
|
||||
}
|
||||
};
|
||||
}
|
||||
return (elementType, lambda, ct) -> mapToString(elementType, operandType, lambda) + mapToString +
|
||||
".collect(" + CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS + ".joining())";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String mapToString(PsiType elementType, PsiType resultType, String lambda) {
|
||||
return "." + getMapOperationName(elementType, resultType) + "(" + lambda + ")";
|
||||
}
|
||||
|
||||
private static class FoldExpressionIntoStreamFix implements LocalQuickFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.fold.expression.into.stream.fix.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiPolyadicExpression expression = tryCast(descriptor.getStartElement(), PsiPolyadicExpression.class);
|
||||
if (expression == null) return;
|
||||
TerminalGenerator generator = getGenerator(expression);
|
||||
if (generator == null) return;
|
||||
List<PsiExpression> diffs = extractDiff(generator, expression);
|
||||
if (diffs.isEmpty()) return;
|
||||
|
||||
PsiExpression[] operands = expression.getOperands();
|
||||
PsiExpression firstExpression = diffs.get(0);
|
||||
assert PsiTreeUtil.isAncestor(operands[0], firstExpression, true);
|
||||
Object marker = new Object();
|
||||
PsiTreeUtil.mark(firstExpression, marker);
|
||||
CommentTracker ct = new CommentTracker();
|
||||
PsiExpression operandCopy = (PsiExpression)ct.markUnchanged(operands[0]).copy();
|
||||
PsiElement expressionCopy = PsiTreeUtil.releaseMark(operandCopy, marker);
|
||||
if (expressionCopy == null) return;
|
||||
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
PsiType elementType = firstExpression.getType();
|
||||
SuggestedNameInfo info = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, elementType, true);
|
||||
String name = info.names.length > 0 ? info.names[0] : "v";
|
||||
name = codeStyleManager.suggestUniqueVariableName(name, expression, true);
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
expressionCopy.replace(factory.createExpressionFromText(name, expressionCopy));
|
||||
String lambda = name + "->" + operandCopy.getText();
|
||||
String streamClass = StreamApiUtil.getStreamClassForType(elementType);
|
||||
if (streamClass == null) return;
|
||||
String source = streamClass + "." + (elementType instanceof PsiClassType ? "<" + elementType.getCanonicalText() + ">" : "")
|
||||
+ "of" + StreamEx.of(diffs).map(ct::text).joining(",", "(", ")");
|
||||
String fullStream = source + generator.generateTerminal(elementType, lambda, ct);
|
||||
PsiElement result = ct.replaceAndRestoreComments(expression, fullStream);
|
||||
cleanup(result);
|
||||
}
|
||||
|
||||
private static void cleanup(PsiElement result) {
|
||||
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(result.getProject());
|
||||
result = SimplifyStreamApiCallChainsInspection.simplifyStreamExpressions(result);
|
||||
LambdaCanBeMethodReferenceInspection.replaceAllLambdasWithMethodReferences(result);
|
||||
result = codeStyleManager.shortenClassReferences(result);
|
||||
PsiDiamondTypeUtil.removeRedundantTypeArguments(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1091,17 +1091,10 @@ public class StreamApiMigrationInspection extends AbstractBaseJavaLocalInspectio
|
||||
PsiType type = myExpression.getType();
|
||||
if (type instanceof PsiArrayType) {
|
||||
PsiType componentType = ((PsiArrayType)type).getComponentType();
|
||||
if (componentType.equals(PsiType.INT)) {
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM + ".of(" + initializerText + ")";
|
||||
}
|
||||
else if (componentType.equals(PsiType.LONG)) {
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM + ".of(" + initializerText + ")";
|
||||
}
|
||||
else if (componentType.equals(PsiType.DOUBLE)) {
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM + ".of(" + initializerText + ")";
|
||||
}
|
||||
else if (componentType instanceof PsiClassType) {
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_STREAM + ".<" + componentType.getCanonicalText() + ">of(" + initializerText + ")";
|
||||
String streamClass = StreamApiUtil.getStreamClassForType(componentType);
|
||||
if (streamClass != null) {
|
||||
return streamClass + "." + (componentType instanceof PsiClassType ? "<" + componentType.getCanonicalText() + ">" : "")
|
||||
+ ".of(" + initializerText + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1307,25 +1300,7 @@ public class StreamApiMigrationInspection extends AbstractBaseJavaLocalInspectio
|
||||
}
|
||||
String maybeCondition = myCondition != null ? ct.lambdaText(myVariable, myCondition) + "," : "";
|
||||
|
||||
return getStreamClass(myVariable.getType()) + ".iterate(" + ct.text(myInitializer) + "," + maybeCondition + lambda + ")";
|
||||
}
|
||||
|
||||
@Contract(value = "null -> null", pure = true)
|
||||
private static String getStreamClass(@Nullable PsiType type) {
|
||||
if (type == null) return null;
|
||||
if (ClassUtils.isPrimitive(type)) {
|
||||
if (type.equals(PsiType.INT)) {
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM;
|
||||
}
|
||||
else if (type.equals(PsiType.DOUBLE)) {
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM;
|
||||
}
|
||||
else if (type.equals(PsiType.LONG)) {
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_STREAM;
|
||||
return StreamApiUtil.getStreamClassForType(myVariable.getType()) + ".iterate(" + ct.text(myInitializer) + "," + maybeCondition + lambda + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1358,7 +1333,7 @@ public class StreamApiMigrationInspection extends AbstractBaseJavaLocalInspectio
|
||||
if (initStmt == null || initStmt.getDeclaredElements().length != 1) return null;
|
||||
PsiLocalVariable variable = tryCast(initStmt.getDeclaredElements()[0], PsiLocalVariable.class);
|
||||
if (variable == null) return null;
|
||||
if (getStreamClass(variable.getType()) == null) return null;
|
||||
if (StreamApiUtil.getStreamClassForType(variable.getType()) == null) return null;
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer == null) return null;
|
||||
PsiStatement update = forStatement.getUpdate();
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>Reports expressions with repeating pattern which could be replaced with Stream API.</p>
|
||||
<!-- tooltip end -->
|
||||
<p><small>New in 2018.2</small></p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
boolean foo(String a, String b, String c, String d) {
|
||||
return Stream.of(a, b, c, d).allMatch(s -> s.startsWith("xyz"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
boolean foo(double[] arr) {
|
||||
return IntStream.of(1, 3, 7, 9).allMatch(i -> arr[i] >= 5);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
boolean foo(String a, String b, String c, String d) {
|
||||
return Stream.of(a, b, c, d).noneMatch(s -> s.startsWith("xyz"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
String foo(String a, String b, String c, String d) {
|
||||
return Stream.of(a, b, c, d).map(String::trim).collect(Collectors.joining());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
String foo(int a, int b, int c, int d) {
|
||||
return IntStream.of(a, b, c, d).map(i -> i * 2).mapToObj(String::valueOf).collect(Collectors.joining("|"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
boolean foo(String a, String b, String c, String d) {
|
||||
return Stream.of(a, b, c, d).noneMatch(s -> s.startsWith("xyz"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
int foo(String a, String b, String c, String d) {
|
||||
return Stream.of(a, b, c, d).mapToInt(String::length).sum();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
boolean foo(String a, String b, String c, String d) {
|
||||
return a.startsWith("xyz") &<caret>& b.startsWith("xyz") && c.startsWith("xyz") && d.startsWith("xyz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
boolean foo(double[] arr) {
|
||||
return arr[1] >= 5 && arr[3] >= 5 && arr[7] >= 5 && arr[9] <caret>>= 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
boolean foo(String a, String b, String c, String d) {
|
||||
return !a.startsWith("xyz") &<caret>& !b.startsWith("xyz") && !c.startsWith("xyz") && !d.startsWith("xyz");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
String foo(String a, String b, String c, String d) {
|
||||
return a.trim()+b.trim()+c.trim()+<caret>d.trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
String foo(int a, int b, int c, int d) {
|
||||
return a * 2 + "|" + b * 2 + "|" + c * 2 + "|"<caret> + d * 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
boolean foo(String a, String b, String c, String d) {
|
||||
return !(a.startsWith("xyz") |<caret>| b.startsWith("xyz") || c.startsWith("xyz") || d.startsWith("xyz"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fold expression into Stream chain" "false"
|
||||
class Test {
|
||||
boolean foo(String a, String b, String c, String d) {
|
||||
return a == null || b == null || c == null || d == <caret>null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fold expression into Stream chain" "true"
|
||||
class Test {
|
||||
int foo(String a, String b, String c, String d) {
|
||||
return a.length()+b.length()+c.length()+<caret>d.length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.java.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.streamMigration.FoldExpressionIntoStreamInspection;
|
||||
import com.intellij.codeInspection.streamToLoop.StreamToLoopInspection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class FoldExpressionIntoStreamInspectionTest extends LightQuickFixParameterizedTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new FoldExpressionIntoStreamInspection()};
|
||||
}
|
||||
|
||||
public void test() { doAllTests(); }
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/foldIntoStream";
|
||||
}
|
||||
}
|
||||
@@ -954,3 +954,5 @@ inspection.capturing.cleaner.description=Cleaner captures object reference
|
||||
|
||||
inspection.redundant.explicit.close=Redundant close
|
||||
inspection.redundant.explicit.close.fix.name=Remove redundant close
|
||||
inspection.fold.expression.into.stream.display.name=Expression can be folded into Stream chain
|
||||
inspection.fold.expression.into.stream.fix.name=Fold expression into Stream chain
|
||||
|
||||
@@ -703,7 +703,11 @@ public class EquivalenceChecker {
|
||||
if (qualifier2 == null) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
return expressionsMatch(qualifier1, qualifier2);
|
||||
Match match = expressionsMatch(qualifier1, qualifier2);
|
||||
if (match.isExactMismatch()) {
|
||||
return new Match(qualifier1, qualifier2);
|
||||
}
|
||||
return match;
|
||||
}
|
||||
else {
|
||||
if (qualifier2 != null && !(qualifier2 instanceof PsiThisExpression || qualifier2 instanceof PsiSuperExpression)) {
|
||||
|
||||
@@ -74,6 +74,26 @@ public class StreamApiUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Stream API class name (Stream, LongStream, IntStream, DoubleStream) which corresponds to given element type,
|
||||
* or null if there's no corresponding Stream API class.
|
||||
*
|
||||
* @param type stream element type
|
||||
* @return a fully-qualified class name
|
||||
*/
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
public static String getStreamClassForType(@Nullable PsiType type) {
|
||||
if(type == null) return null;
|
||||
if(type instanceof PsiPrimitiveType) {
|
||||
if(type.equals(PsiType.INT)) return CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM;
|
||||
if(type.equals(PsiType.LONG)) return CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM;
|
||||
if(type.equals(PsiType.DOUBLE)) return CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM;
|
||||
return null;
|
||||
}
|
||||
return CommonClassNames.JAVA_UTIL_STREAM_STREAM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns call from call chain which name satisfies isWantedCall predicate.
|
||||
* Also checks that all calls between start call and wanted call satisfies isAllowedIntermediateCall
|
||||
|
||||
Reference in New Issue
Block a user