void (@NotNull IElementType op, PsiExpression lExpr, @Nullable PsiType lType, PsiExpression rExpr, @Nullable PsiType rType) { boolean comparing = op == JavaTokenType.EQEQ || op == JavaTokenType.NE; boolean comparingRef = comparing && !TypeConversionUtil.isPrimitiveAndNotNull(lType) && !TypeConversionUtil.isPrimitiveAndNotNull(rType); boolean comparingPrimitiveNumeric = !comparingRef && ComparisonUtils.isComparisonOperation(op) && TypeConversionUtil.isNumericType(lType) && TypeConversionUtil.isNumericType(rType); // comparing object and primitive is not compilable code, but we try to balance types to avoid noise warnings boolean comparingObjectAndPrimitive = comparing && !comparingRef && !comparingPrimitiveNumeric && (TypeConversionUtil.isNumericType(lType) || TypeConversionUtil.isNumericType(rType)); boolean shift = op == JavaTokenType.GTGT || op == JavaTokenType.LTLT || op == JavaTokenType.GTGTGT; PsiType leftCast = null; PsiType rightCast = null; if (comparingObjectAndPrimitive) { leftCast = rightCast = TypeConversionUtil.isNumericType(lType) ? rType : lType; } else if (shift) { leftCast = PsiTypes.longType().equals(PsiPrimitiveType.getOptionallyUnboxedType(lType)) ? PsiTypes.longType() : PsiTypes.intType(); rightCast = PsiTypes.longType().equals(PsiPrimitiveType.getOptionallyUnboxedType(rType)) ? PsiTypes.longType() : PsiTypes.intType(); } else if (!comparingRef) { leftCast = rightCast = TypeConversionUtil.unboxAndBalanceTypes(lType, rType); } if (leftCast != null) { generateBoxingUnboxingInstructionFor(lExpr, lType, leftCast, false); } rExpr.accept(this); if (rightCast != null) { generateBoxingUnboxingInstructionFor(rExpr, rType, rightCast, false); } }