mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
BoolUtils: make it recognize methods with negated counterparts: IDEA-199888
This commit is contained in:
+9
@@ -0,0 +1,9 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Foo {
|
||||
void m(Stream<String> s) {
|
||||
if (s.anyMatch(str -> str.equals("foo")).not<caret>) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Foo {
|
||||
void m(Stream<String> s) {
|
||||
if (s.noneMatch(str -> str.equals("foo"))<caret>) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import java.util.Optional;
|
||||
|
||||
public class Foo {
|
||||
void m() {
|
||||
if (Optional.of("").isPresent().not<caret>) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import java.util.Optional;
|
||||
|
||||
public class Foo {
|
||||
void m() {
|
||||
if (Optional.of("").isEmpty()<caret>) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.java.codeInsight.template.postfix.templates;
|
||||
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -46,5 +47,39 @@ public class NotExpressionPostfixTemplateTest extends PostfixTemplateTestCase {
|
||||
public void testConditionInBooleanMethodCall() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSmartNegationPresentEmpty() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSmartNegationNoneAny() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.addClass("package java.util;\n" +
|
||||
"public class Optional<T> {\n" +
|
||||
" public static <T> Optional<T> of(T value) { return null; }\n" +
|
||||
" public boolean isPresent() { return true; }\n" +
|
||||
" public boolean isEmpty() { return false; }\n" +
|
||||
"}");
|
||||
myFixture.addClass("package java.util.stream;\n" +
|
||||
"\n" +
|
||||
"import java.util.function.Predicate;\n" +
|
||||
"\n" +
|
||||
"public class Stream<T> {\n" +
|
||||
" boolean anyMatch(Predicate<? super T> predicate) { return true;}\n" +
|
||||
" boolean noneMatch(Predicate<? super T> predicate) { return false;}\n" +
|
||||
"}");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return JAVA_11;
|
||||
}
|
||||
|
||||
// public void testNegation() { doTest(); } // todo: test for chooser
|
||||
}
|
||||
+70
@@ -17,15 +17,23 @@ package com.siyeh.ig.psiutils;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.intellij.psi.CommonClassNames.JAVA_UTIL_OPTIONAL;
|
||||
|
||||
public class BoolUtils {
|
||||
|
||||
private BoolUtils() {}
|
||||
@@ -74,6 +82,64 @@ public class BoolUtils {
|
||||
return getNegatedExpressionText(condition, ParenthesesUtils.NUM_PRECEDENCES, tracker);
|
||||
}
|
||||
|
||||
private static final CallMatcher STREAM_ANY_MATCH = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_STREAM_STREAM, "anyMatch");
|
||||
private static final CallMatcher STREAM_NONE_MATCH = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_STREAM_STREAM, "noneMatch");
|
||||
|
||||
|
||||
private static final String OPTIONAL_INT = "java.util.OptionalInt";
|
||||
private static final String OPTIONAL_LONG = "java.util.OptionalLong";
|
||||
private static final String OPTIONAL_DOUBLE = "java.util.OptionalDouble";
|
||||
|
||||
private static final CallMatcher OPTIONAL_IS_PRESENT =
|
||||
CallMatcher.anyOf(
|
||||
CallMatcher.exactInstanceCall(JAVA_UTIL_OPTIONAL, "isPresent").parameterCount(0),
|
||||
CallMatcher.exactInstanceCall(OPTIONAL_INT, "isPresent").parameterCount(0),
|
||||
CallMatcher.exactInstanceCall(OPTIONAL_LONG, "isPresent").parameterCount(0),
|
||||
CallMatcher.exactInstanceCall(OPTIONAL_DOUBLE, "isPresent").parameterCount(0)
|
||||
);
|
||||
private static final CallMatcher OPTIONAL_IS_EMPTY =
|
||||
CallMatcher.anyOf(
|
||||
CallMatcher.exactInstanceCall(JAVA_UTIL_OPTIONAL, "isEmpty").parameterCount(0),
|
||||
CallMatcher.exactInstanceCall(OPTIONAL_INT, "isEmpty").parameterCount(0),
|
||||
CallMatcher.exactInstanceCall(OPTIONAL_LONG, "isEmpty").parameterCount(0),
|
||||
CallMatcher.exactInstanceCall(OPTIONAL_DOUBLE, "isEmpty").parameterCount(0)
|
||||
);
|
||||
|
||||
private static Predicate<PsiMethodCallExpression> withMinimalLanguageLevel(CallMatcher matcher, LanguageLevel level) {
|
||||
return matcher.and(expression -> PsiUtil.getLanguageLevel(expression).isAtLeast(level));
|
||||
}
|
||||
|
||||
private static class PredicatedReplacement {
|
||||
Predicate<PsiMethodCallExpression> predicate;
|
||||
String name;
|
||||
|
||||
private PredicatedReplacement(Predicate<PsiMethodCallExpression> predicate, String name) {
|
||||
this.predicate = predicate;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<PredicatedReplacement> ourReplacements = new ArrayList<>();
|
||||
static {
|
||||
ourReplacements.add(new PredicatedReplacement(OPTIONAL_IS_EMPTY, "isPresent"));
|
||||
ourReplacements.add(new PredicatedReplacement(withMinimalLanguageLevel(OPTIONAL_IS_PRESENT, LanguageLevel.JDK_11), "isEmpty"));
|
||||
ourReplacements.add(new PredicatedReplacement(STREAM_ANY_MATCH, "noneMatch"));
|
||||
ourReplacements.add(new PredicatedReplacement(STREAM_NONE_MATCH, "anyMatch"));
|
||||
}
|
||||
|
||||
private static String findSmartMethodNegation(PsiExpression expression) {
|
||||
if (!(expression instanceof PsiMethodCallExpression)) return null;
|
||||
PsiMethodCallExpression call = (PsiMethodCallExpression)expression;
|
||||
PsiMethodCallExpression copy = (PsiMethodCallExpression)call.copy();
|
||||
for (PredicatedReplacement predicatedReplacement : ourReplacements) {
|
||||
if (predicatedReplacement.predicate.test(call)) {
|
||||
ExpressionUtils.bindCallTo(copy, predicatedReplacement.name);
|
||||
return copy.getText();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNegatedExpressionText(@Nullable PsiExpression expression,
|
||||
int precedence,
|
||||
@@ -81,6 +147,10 @@ public class BoolUtils {
|
||||
if (expression == null) {
|
||||
return "";
|
||||
}
|
||||
if (expression instanceof PsiMethodCallExpression) {
|
||||
String smartNegation = findSmartMethodNegation(expression);
|
||||
if (smartNegation != null) return smartNegation;
|
||||
}
|
||||
if (expression instanceof PsiParenthesizedExpression) {
|
||||
final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression;
|
||||
PsiExpression operand = parenthesizedExpression.getExpression();
|
||||
|
||||
Reference in New Issue
Block a user