@Contract(value = "null, _ -> false; _, null -> false", pure = true)
  public static boolean areExpressionsOpposite(@Nullable PsiExpression expression1, @Nullable PsiExpression expression2) {
    expression1 = PsiUtil.skipParenthesizedExprDown(expression1);
    expression2 = PsiUtil.skipParenthesizedExprDown(expression2);
    if (expression1 == null || expression2 == null) return false;
    EquivalenceChecker equivalence = EquivalenceChecker.getCanonicalPsiEquivalence();
    if (isNegation(expression1)) {
      return equivalence.expressionsAreEquivalent(getNegated(expression1), expression2);
    }
    if (isNegation(expression2)) {
      return equivalence.expressionsAreEquivalent(getNegated(expression2), expression1);
    }
    if (expression1 instanceof PsiBinaryExpression binOp1 && expression2 instanceof PsiBinaryExpression binOp2) {
      RelationType rel1 = DfaPsiUtil.getRelationByToken(binOp1.getOperationTokenType());
      RelationType rel2 = DfaPsiUtil.getRelationByToken(binOp2.getOperationTokenType());
      if (rel1 == null || rel2 == null) return false;
      PsiType type = binOp1.getLOperand().getType();
      // a > b and a <= b are not strictly opposite due to NaN semantics
      if (type == null || type.equals(PsiTypes.floatType()) || type.equals(PsiTypes.doubleType())) return false;
      if (rel1 == rel2.getNegated()) {
        return equivalence.expressionsAreEquivalent(binOp1.getLOperand(), binOp2.getLOperand()) &&
               equivalence.expressionsAreEquivalent(binOp1.getROperand(), binOp2.getROperand());
      }
      if (rel1.getFlipped() == rel2.getNegated()) {
        return equivalence.expressionsAreEquivalent(binOp1.getLOperand(), binOp2.getROperand()) &&
               equivalence.expressionsAreEquivalent(binOp1.getROperand(), binOp2.getLOperand());
      }
    }
    return false;
  }
@Contract(value = "null, _ -> false; _, null -> false", pure = true)
  public static boolean areExpressionsOpposite(@Nullable PsiExpression expression1, @Nullable PsiExpression expression2)