private static CauseItem findRangeCause(MemoryStateChange factUse, DfaValue value, LongRangeSet range, @Nls String template) {
    if (value instanceof DfaTypeValue && factUse.myInstruction.getIndex() == -1) {
      return null;
    }
    if (value instanceof DfaVariableValue) {
      VariableDescriptor descriptor = ((DfaVariableValue)value).getDescriptor();
      if (descriptor instanceof SpecialField && range.equals(JvmPsiRangeSetUtil.indexRange())) {
        switch (((SpecialField)descriptor)) {
          case ARRAY_LENGTH -> {
            return new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.array.length.is.always.non.negative"), factUse);
          }
          case STRING_LENGTH -> {
            return new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.string.length.is.always.non.negative"), factUse);
          }
          case COLLECTION_SIZE -> {
            return new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.collection.size.is.always.non.negative"), factUse);
          }
          default -> {
          }
        }
      }
    }
    PsiExpression expression = factUse.myTopOfStack == value ? factUse.getExpression() : null;
    if (expression != null) {
      PsiType type = expression.getType();
      if (expression instanceof PsiLiteralExpression) {
        return null; // Literal range is quite evident
      }
      if (expression instanceof PsiMethodCallExpression call) {
        PsiMethod method = call.resolveMethod();
        if (method != null) {
          LongRangeSet fromAnnotation = JvmPsiRangeSetUtil.fromPsiElement(method);
          if (fromAnnotation.equals(range)) {
            return new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.range.is.specified.by.annotation", method.getName(), range),
                                 call.getMethodExpression().getReferenceNameElement());
          }
        }
      }
      if (expression instanceof PsiTypeCastExpression && type instanceof PsiPrimitiveType && TypeConversionUtil.isNumericType(type)) {
        PsiExpression operand = ((PsiTypeCastExpression)expression).getOperand();
        MemoryStateChange operandPush = factUse.findExpressionPush(operand);
        if (operandPush != null) {
          DfaValue castedValue = operandPush.myTopOfStack;
          FactDefinition<LongRangeSet> operandInfo = operandPush.findFact(castedValue, FactExtractor.range());
          LongRangeSet operandRange = operandInfo.myFact;
          LongRangeSet result = JvmPsiRangeSetUtil.castTo(operandRange, (PsiPrimitiveType)type);
          if (range.equals(result)) {
            CauseItem cause =
              new CauseItem(new RangeDfaProblemType(
                JavaAnalysisBundle.message("dfa.find.cause.result.of.primitive.cast.template", type.getCanonicalText()), range, null),
                            expression);
            if (!operandRange.equals(JvmPsiRangeSetUtil.typeRange(operand.getType()))) {
              cause.addChildren(findRangeCause(operandPush, castedValue, operandRange,
                                               JavaAnalysisBundle.message("dfa.find.cause.numeric.cast.operand.template")));
            }
            return cause;
          }
        }
      }
      if (range.equals(JvmPsiRangeSetUtil.typeRange(type))) {
        return null; // Range is any value of given type: no need to explain (except narrowing cast)
      }
      if (PsiTypes.longType().equals(type) || PsiTypes.intType().equals(type)) {
        if (expression instanceof PsiBinaryExpression binOp) {
          LongRangeType lrType = PsiTypes.longType().equals(type) ? LongRangeType.INT64 : LongRangeType.INT32;
          PsiExpression left = PsiUtil.skipParenthesizedExprDown(binOp.getLOperand());
          PsiExpression right = PsiUtil.skipParenthesizedExprDown(binOp.getROperand());
          MemoryStateChange leftPush = factUse.findExpressionPush(left);
          MemoryStateChange rightPush = factUse.findExpressionPush(right);
          if (leftPush != null && rightPush != null) {
            DfaValue leftVal = leftPush.myTopOfStack;
            FactDefinition<LongRangeSet> leftSet = leftPush.findFact(leftVal, FactExtractor.range());
            DfaValue rightVal = rightPush.myTopOfStack;
            FactDefinition<LongRangeSet> rightSet = rightPush.findFact(rightVal, FactExtractor.range());
            LongRangeSet fromType = Objects.requireNonNull(JvmPsiRangeSetUtil.typeRange(type));
            LongRangeSet leftRange = leftSet.myFact.meet(fromType);
            LongRangeSet rightRange = rightSet.myFact.meet(fromType);
            LongRangeBinOp op = JvmPsiRangeSetUtil.binOpFromToken(binOp.getOperationTokenType());
            if (op != null) {
              LongRangeSet result = op.eval(leftRange, rightRange, lrType);
              if (range.equals(result)) {
                String sign = binOp.getOperationSign().getText();
                CauseItem cause = new CauseItem(new RangeDfaProblemType(
                  JavaAnalysisBundle.message("dfa.find.cause.result.of.numeric.operation.template", sign.equals("%") ? "%%" : sign),
                  range, ObjectUtils.tryCast(type, PsiPrimitiveType.class)), factUse);
                CauseItem leftCause = null, rightCause = null;
                if (!leftRange.equals(fromType)) {
                  leftCause = findRangeCause(leftPush, leftVal, leftRange,
                                             JavaAnalysisBundle.message("dfa.find.cause.left.operand.range.template"));
                }
                if (!rightRange.equals(fromType)) {
                  rightCause = findRangeCause(rightPush, rightVal, rightRange,
                                              JavaAnalysisBundle.message("dfa.find.cause.right.operand.range.template"));
                }
                cause.addChildren(leftCause, rightCause);
                return cause;
              }
            }
          }
        }
      }
    }
    PsiPrimitiveType type = expression != null ? ObjectUtils.tryCast(expression.getType(), PsiPrimitiveType.class) : null;
    CauseItem item = new CauseItem(new RangeDfaProblemType(template, range, type), factUse);
    FactDefinition<LongRangeSet> info = factUse.findFact(value, FactExtractor.range());
    while ((!info.myFact.equals(range))) {
      if (info.myChange == null) break;
      MemoryStateChange previous = info.myChange.getPrevious();
      if (previous == null) break;
      info = previous.findFact(value, FactExtractor.range());
    }
    MemoryStateChange factDef = range.equals(info.myFact) ? info.myChange : null;
    if (factDef != null) {
      if (factDef.myInstruction instanceof AssignInstruction && factDef.myTopOfStack == value) {
        PsiExpression rExpression = ((AssignInstruction)factDef.myInstruction).getRExpression();
        if (rExpression != null) {
          MemoryStateChange rValuePush = factDef.findSubExpressionPush(rExpression);
          if (rValuePush != null) {
            CauseItem assignmentItem = createAssignmentCause((AssignInstruction)factDef.myInstruction, value);
            assignmentItem.addChildren(findRangeCause(rValuePush, rValuePush.myTopOfStack, range,
                                                      JavaAnalysisBundle.message("dfa.find.cause.numeric.range.generic.template")));
            item.addChildren(assignmentItem);
            return item;
          }
        }
      }
      PsiExpression defExpression = factDef.getExpression();
      if (defExpression != null) {
        item.addChildren(new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.range.is.known.from.place"), defExpression));
      }
    }
    return item;
  }
private static CauseItem findRangeCause(MemoryStateChange factUse, DfaValue value, LongRangeSet range, @Nls String template)