private CauseItem[] findBooleanResultCauses(@NotNull PsiExpression expression,
                                              @NotNull MemoryStateChange history,
                                              boolean value) {
    if (BoolUtils.isNegation(expression)) {
      PsiExpression negated = BoolUtils.getNegated(expression);
      if (negated != null) {
        MemoryStateChange negatedPush = history.findExpressionPush(negated);
        if (negatedPush != null) {
          CauseItem cause = new CauseItem(
            JavaAnalysisBundle.message("dfa.find.cause.value.x.is.always.the.same", negated.getText(), !value), negated);
          cause.addChildren(findConstantValueCause(negated, negatedPush, !value));
          return new CauseItem[]{cause};
        }
      }
    }
    if (expression instanceof PsiPolyadicExpression) {
      IElementType tokenType = ((PsiPolyadicExpression)expression).getOperationTokenType();
      boolean and = tokenType.equals(JavaTokenType.ANDAND);
      if (and || tokenType.equals(JavaTokenType.OROR)) {
        if (value != and) {
          MemoryStateChange push = history;
          if (history.myInstruction instanceof ResultOfInstruction) {
            MemoryStateChange previous = history.getPrevious();
            if (previous != null) {
              previous = previous.getNonMerge();
            }
            if (previous != null && previous.myInstruction instanceof GotoInstruction) {
              previous = previous.getPrevious();
            }
            if (previous != null) {
              push = previous;
            }
          }
          if (push.myInstruction instanceof PushValueInstruction pushValueInstruction && pushValueInstruction.getValue().isConst(value) &&
              pushValueInstruction.getDfaAnchor() instanceof JavaExpressionAnchor anchor &&
              anchor.getExpression() == expression) {
            push = push.getPrevious();
          }
          if (push != null) {
            push = push.getNonMerge();
          }
          if (push != null && push.myInstruction instanceof ConditionalGotoInstruction) {
            push = push.getPrevious();
          }
          if (push != null &&
              push.myInstruction instanceof ExpressionPushingInstruction instruction &&
              instruction.getDfaAnchor() instanceof JavaExpressionAnchor anchor) {
            PsiExpression operand = anchor.getExpression();
            if (expression.equals(PsiUtil.skipParenthesizedExprUp(operand.getParent()))) {
              int i =
                IntStreamEx.ofIndices(((PsiPolyadicExpression)expression).getOperands(), e -> PsiTreeUtil.isAncestor(e, operand, false))
                  .findFirst().orElse(-1);
              if (i >= 0) {
                CauseItem cause = new CauseItem(
                  JavaAnalysisBundle.message("dfa.find.cause.operand.of.boolean.expression.is.the.same", i + 1, and ? 0 : 1, value),
                  operand);
                cause.addChildren(findConstantValueCause(operand, push, value));
                return new CauseItem[]{cause};
              }
            }
          }
          return new CauseItem[0];
        }
        PsiExpression[] operands = ((PsiPolyadicExpression)expression).getOperands();
        List<CauseItem> operandCauses = new ArrayList<>();
        for (int i = 0; i < operands.length; i++) {
          PsiExpression operand = operands[i];
          operand = PsiUtil.skipParenthesizedExprDown(operand);
          MemoryStateChange push = history.findExpressionPush(operand);
          if (push != null &&
              ((push.myInstruction instanceof ConditionalGotoInstruction gotoInstruction &&
                gotoInstruction.isTarget(DfTypes.booleanValue(value), history.myInstruction)) ||
               push.myTopOfStack.getDfType().isConst(value))) {
            int andVal = and ? 1 : 0;
            CauseItem cause = new CauseItem(
              JavaAnalysisBundle.message("dfa.find.cause.operand.of.boolean.expression.is.the.same", i + 1, andVal == 1 ? 0 : 1, value),
              operand);
            cause.addChildren(findBooleanResultCauses(operand, push, value));
            operandCauses.add(cause);
          }
        }
        if (operandCauses.size() == operands.length) {
          return operandCauses.toArray(new CauseItem[0]);
        }
      }
    }
    if (expression instanceof PsiBinaryExpression binOp) {
      RelationType relationType =
        DfaPsiUtil.getRelationByToken(binOp.getOperationTokenType());
      if (relationType != null) {
        if (!value) {
          relationType = relationType.getNegated();
        }
        PsiExpression leftOperand = PsiUtil.skipParenthesizedExprDown(binOp.getLOperand());
        PsiExpression rightOperand = PsiUtil.skipParenthesizedExprDown(binOp.getROperand());
        MemoryStateChange leftChange = history.findExpressionPush(leftOperand);
        MemoryStateChange rightChange = history.findExpressionPush(rightOperand);
        if (leftChange != null && rightChange != null) {
          DfaValue leftValue = leftChange.myTopOfStack;
          DfaValue rightValue = rightChange.myTopOfStack;
          CauseItem[] causes = findRelationCause(relationType, leftChange, rightChange);
          if (causes.length > 0) {
            return causes;
          }
          if (leftValue == rightValue &&
              (leftValue instanceof DfaVariableValue || leftValue.getDfType() instanceof DfConstantType)) {
            List<CauseItem> constCauses = new ArrayList<>();
            CauseItem leftCause = constantInitializerCause(leftValue, leftChange.getExpression());
            CauseItem rightCause = constantInitializerCause(rightValue, rightChange.getExpression());
            ContainerUtil.addAllNotNull(constCauses, leftCause, rightCause);
            if (constCauses.isEmpty()) {
              return new CauseItem[]{
                new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.comparison.arguments.are.the.same"), binOp.getOperationSign())};
            }
            return constCauses.toArray(new CauseItem[0]);
          }
          if (leftValue != rightValue && relationType.isInequality() &&
              leftValue.getDfType() instanceof DfConstantType && rightValue.getDfType() instanceof DfConstantType) {
            CauseItem causeItem = new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.comparison.arguments.are.different.constants"),
                                                binOp.getOperationSign());
            causeItem.addChildren(constantInitializerCause(leftValue, leftChange.getExpression()),
                                  constantInitializerCause(rightValue, rightChange.getExpression()));
            return new CauseItem[]{causeItem};
          }
        }
      }
    }
    if (expression instanceof PsiInstanceOfExpression instanceOfExpression) {
      PsiExpression operand = instanceOfExpression.getOperand();
      MemoryStateChange operandHistory = history.findExpressionPush(operand);
      if (operandHistory != null) {
        DfaValue operandValue = operandHistory.myTopOfStack;
        if (!value) {
          FactDefinition<DfaNullability> nullability = operandHistory.findFact(operandValue, FactExtractor.nullability());
          if (nullability.myFact == DfaNullability.NULL) {
            CauseItem causeItem = new CauseItem(
              JavaAnalysisBundle.message("dfa.find.cause.value.x.is.always.the.same", operand.getText(), "null"), operand);
            causeItem.addChildren(findConstantValueCause(operand, operandHistory, null));
            return new CauseItem[]{causeItem};
          }
        }
        PsiTypeElement typeElement = instanceOfExpression.getCheckType();
        if (typeElement != null) {
          PsiType type = typeElement.getType();
          CauseItem causeItem = findTypeCause(operandHistory, type, value);
          if (causeItem != null) return new CauseItem[]{causeItem};
        }
      }
    }
    if (expression instanceof PsiMethodCallExpression) {
      return new CauseItem[]{fromCallContract(history, (PsiMethodCallExpression)expression, ContractReturnValue.returnBoolean(value))};
    }
    return new CauseItem[0];
  }
private CauseItem[] findBooleanResultCauses(@NotNull PsiExpression expression,
                                              @NotNull MemoryStateChange history,
                                              boolean value)