public static PsiType calcTypeForBinaryExpression(PsiType lType, PsiType rType, @NotNull IElementType sign, boolean accessLType) {
    if (sign == JavaTokenType.PLUS) {
      // evaluate right argument first, since '+-/*%' is left associative and left operand tends to be bigger
      if (rType == null) {
        if (accessLType) {
          return lType != null && lType.equalsToText(JAVA_LANG_STRING) ? lType : null;
        }
        return NULL_TYPE;
      }
      if (rType.equalsToText(JAVA_LANG_STRING)) {
        return rType;
      }
      if (!accessLType) return NULL_TYPE;
      if (lType == null) return null;
      if (lType.equalsToText(JAVA_LANG_STRING)) {
        return lType;
      }
      return unboxAndBalanceTypes(lType, rType);
    }
    if (sign == JavaTokenType.MINUS || sign == JavaTokenType.ASTERISK || sign == JavaTokenType.DIV || sign == JavaTokenType.PERC) {
      if (rType == null) return null;
      if (!accessLType) return NULL_TYPE;
      if (lType == null) return null;
      return unboxAndBalanceTypes(lType, rType);
    }
    if (sign == JavaTokenType.LTLT || sign == JavaTokenType.GTGT || sign == JavaTokenType.GTGTGT) {
      if (!accessLType) return NULL_TYPE;
      if (lType instanceof PsiClassType) lType = PsiPrimitiveType.getUnboxedType(lType);
      if (PsiTypes.byteType().equals(lType) || PsiTypes.charType().equals(lType) || PsiTypes.shortType().equals(lType)) {
        return PsiTypes.intType();
      }
      return lType;
    }
    if (PsiBinaryExpression.BOOLEAN_OPERATION_TOKENS.contains(sign)) {
      return PsiTypes.booleanType();
    }
    if (sign == JavaTokenType.OR || sign == JavaTokenType.XOR || sign == JavaTokenType.AND) {
      if (rType instanceof PsiClassType) rType = PsiPrimitiveType.getUnboxedType(rType);

      if (lType instanceof PsiClassType) lType = PsiPrimitiveType.getUnboxedType(lType);

      if (rType == null) return null;
      if (PsiTypes.booleanType().equals(rType)) return PsiTypes.booleanType();
      if (!accessLType) return NULL_TYPE;
      if (lType == null) return null;
      if (PsiTypes.booleanType().equals(lType)) return PsiTypes.booleanType();
      if (PsiTypes.longType().equals(lType) || PsiTypes.longType().equals(rType)) return PsiTypes.longType();
      return PsiTypes.intType();
    }
    LOG.error("Unknown token: "+sign);
    return null;
  }
public static PsiType calcTypeForBinaryExpression(PsiType lType, PsiType rType, @NotNull IElementType sign, boolean accessLType)