IDEA-161275 ('Remove double negation' doesn't work)
authorBas Leijdekkers <basleijdekkers@gmail.com>
Thu, 15 Sep 2016 12:45:42 +0000 (14:45 +0200)
committerBas Leijdekkers <basleijdekkers@gmail.com>
Thu, 15 Sep 2016 12:46:23 +0000 (14:46 +0200)
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/DoubleNegationInspection.java
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BoolUtils.java
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ComparisonUtils.java
plugins/InspectionGadgets/test/com/siyeh/igfixes/controlflow/double_negation/DoubleDoubleNegation.after.java [new file with mode: 0644]
plugins/InspectionGadgets/test/com/siyeh/igfixes/controlflow/double_negation/DoubleDoubleNegation.java [new file with mode: 0644]
plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/double_negation/DoubleNegation.java
plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/controlflow/DoubleNegationFixTest.java [new file with mode: 0644]

index ce1bcfca117472ed33b09b83cd9f10ecf48c4631..c0a149e74f57b97df52d44775d87881fc0c75975 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006-2012 Bas Leijdekkers
+ * Copyright 2006-2016 Bas Leijdekkers
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package com.siyeh.ig.controlflow;
 import com.intellij.codeInspection.ProblemDescriptor;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
-import com.intellij.util.IncorrectOperationException;
 import com.siyeh.InspectionGadgetsBundle;
 import com.siyeh.ig.BaseInspection;
 import com.siyeh.ig.BaseInspectionVisitor;
@@ -26,6 +25,7 @@ import com.siyeh.ig.InspectionGadgetsFix;
 import com.siyeh.ig.PsiReplacementUtil;
 import com.siyeh.ig.psiutils.BoolUtils;
 import com.siyeh.ig.psiutils.ParenthesesUtils;
+import com.siyeh.ig.psiutils.TypeUtils;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -68,7 +68,7 @@ public class DoubleNegationInspection extends BaseInspection {
     }
 
     @Override
-    protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+    protected void doFix(Project project, ProblemDescriptor descriptor) {
       final PsiElement expression = descriptor.getPsiElement();
       if (expression instanceof PsiPrefixExpression) {
         final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)expression;
@@ -163,6 +163,9 @@ public class DoubleNegationInspection extends BaseInspection {
   }
 
   static boolean isNegation(PsiPolyadicExpression expression) {
+    for (PsiExpression operand : expression.getOperands()) {
+      if (TypeUtils.hasFloatingPointType(operand)) return false; // don't change semantics for NaNs
+    }
     return JavaTokenType.NE.equals(expression.getOperationTokenType());
   }
 }
\ No newline at end of file
index 7f093941dec3f830ee07bc85a4b156c96621e5a8..6ae9952c2cac8eab0c612066f05930be30d47222 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2015 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@ package com.siyeh.ig.psiutils;
 
 import com.intellij.psi.*;
 import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.util.TypeConversionUtil;
 import org.jetbrains.annotations.Contract;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
@@ -85,8 +84,7 @@ public class BoolUtils {
       }
       return ParenthesesUtils.getText(negated, precedence);
     }
-    else if (ComparisonUtils.isComparison(expression) &&
-             !TypeConversionUtil.isFloatOrDoubleType(ComparisonUtils.getComparisonType(expression))) {
+    else if (ComparisonUtils.isComparison(expression)) {
       final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
       final String negatedComparison = ComparisonUtils.getNegatedComparison(polyadicExpression.getOperationTokenType());
       final StringBuilder result = new StringBuilder();
@@ -94,6 +92,10 @@ public class BoolUtils {
       final boolean isEven = (operands.length & 1) != 1;
       for (int i = 0, length = operands.length; i < length; i++) {
         final PsiExpression operand = operands[i];
+        if (TypeUtils.hasFloatingPointType(operand)) {
+          // preserve semantics for NaNs
+          return "!(" + polyadicExpression.getText() + ')';
+        }
         if (i > 0) {
           if (isEven && (i & 1) != 1) {
             final PsiJavaToken token = polyadicExpression.getTokenBeforeOperand(operand);
index 78e5e1d02d082afd464f1ea134caa82a57c40547..889f4fc48f924011a39de044a780512fa9a4d76c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 package com.siyeh.ig.psiutils;
 
-import com.intellij.psi.*;
+import com.intellij.psi.JavaTokenType;
+import com.intellij.psi.PsiExpression;
+import com.intellij.psi.PsiPolyadicExpression;
 import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.util.TypeConversionUtil;
-import org.jetbrains.annotations.Contract;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -60,37 +60,6 @@ public class ComparisonUtils {
     s_invertedComparisons.put(JavaTokenType.LE, ">");
   }
 
-  /**
-   * Returns the actual type of compared values in comparison expression after unboxing and promotion if applicable.
-   *
-   * @param expression the expression to get the type of compared values
-   * @return the resulting type or null if expression is not a comparison or type is not known.
-   */
-  @Contract("null -> null")
-  @Nullable
-  public static PsiType getComparisonType(PsiExpression expression) {
-    if(!(expression instanceof PsiPolyadicExpression)) return null;
-    PsiPolyadicExpression operation = (PsiPolyadicExpression)expression;
-    IElementType tokenType = operation.getOperationTokenType();
-    if (!isComparisonOperation(tokenType)) return null;
-    PsiType lType;
-    PsiType rType;
-    if(operation instanceof PsiBinaryExpression) {
-      PsiExpression left = ((PsiBinaryExpression)operation).getLOperand();
-      PsiExpression right = ((PsiBinaryExpression)operation).getROperand();
-      lType = left.getType();
-      rType = right == null ? null : right.getType();
-    } else {
-      PsiExpression[] operands = operation.getOperands();
-      if(operands.length <= 2) return null;
-      lType = PsiType.BOOLEAN;
-      rType = operands[operands.length-1].getType();
-    }
-    if (lType == null || rType == null) return null;
-    if (lType.equals(rType)) return lType;
-    return TypeConversionUtil.unboxAndBalanceTypes(lType, rType);
-  }
-
   public static boolean isComparison(@Nullable PsiExpression expression) {
     if (!(expression instanceof PsiPolyadicExpression)) {
       return false;
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/controlflow/double_negation/DoubleDoubleNegation.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/controlflow/double_negation/DoubleDoubleNegation.after.java
new file mode 100644 (file)
index 0000000..16c2a61
--- /dev/null
@@ -0,0 +1,5 @@
+class X {
+  void vm(Double a, Double b) {
+    boolean r = a == null || b != null;
+  }
+}
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/controlflow/double_negation/DoubleDoubleNegation.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/controlflow/double_negation/DoubleDoubleNegation.java
new file mode 100644 (file)
index 0000000..4604a99
--- /dev/null
@@ -0,0 +1,5 @@
+class X {
+  void vm(Double a, Double b) {
+    boolean r = !(<caret>a != null) || b != null;
+  }
+}
\ No newline at end of file
index 60f27f2808114bc43d849f82a1341dbe1280b79f..0fc7f88eeb229590a1627bb8dfde7a81654e03f7 100644 (file)
@@ -9,4 +9,8 @@ public class DoubleNegation {
     boolean r4 = (<warning descr="Double negation in 'b1 != (b2 != b3)'">b1 != (b2 != b3)</warning>);
     boolean r5 = (<warning descr="Double negation in 'b1 != b2 != b3'">b1 != b2 != b3</warning>);
   }
+
+  void vm(Double a, double b) {
+    boolean r = <warning descr="Double negation in '!(a != null)'">!(a != null)</warning> || !(b != Double.NaN != false);
+  }
 }
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/controlflow/DoubleNegationFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/controlflow/DoubleNegationFixTest.java
new file mode 100644 (file)
index 0000000..53f0fdb
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2016 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.siyeh.ig.fixes.controlflow;
+
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.IGQuickFixesTestCase;
+import com.siyeh.ig.controlflow.DoubleNegationInspection;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class DoubleNegationFixTest extends IGQuickFixesTestCase {
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    myFixture.enableInspections(new DoubleNegationInspection());
+    myRelativePath = "controlflow/double_negation";
+    myDefaultHint = InspectionGadgetsBundle.message("double.negation.quickfix");
+  }
+
+  public void testDoubleDoubleNegation() { doTest(); }
+}