Index: wp-includes/category.php
===================================================================
--- wp-includes/category.php	(revision 4644)
+++ wp-includes/category.php	(working copy)
@@ -21,7 +21,7 @@
 
 	$defaults = array('type' => 'post', 'child_of' => 0, 'orderby' => 'name', 'order' => 'ASC',
 		'hide_empty' => true, 'include_last_update_time' => false, 'hierarchical' => 1, 'exclude' => '', 'include' => '',
-		'number' => '');
+		'number' => '', 'pad_counts' => false);
 	$r = array_merge($defaults, $r);
 	if ( 'count' == $r['orderby'] )
 		$r['orderby'] = 'category_count';
@@ -109,17 +109,21 @@
 		$categories = & _get_cat_children($child_of, $categories);
 
 	// Update category counts to include children.
-	if ( $hierarchical ) {
+	if ( $pad_counts )
+		pad_category_counts($type, $categories);
+
+	// Make sure we show empty categories that have children.
+	if ( $hierarchical && $hide_empty ) {
 		foreach ( $categories as $k => $category ) {
-			$progeny = 'link' == $type ? $category->link_count : $category->category_count;
-			if ( $children = _get_cat_children($category->cat_ID, $categories) ) {
+			if ( ! $category->{'link' == $type ? 'link_count' : 'category_count'} ) {
+				$children = _get_cat_children($category->cat_ID, $categories);
 				foreach ( $children as $child )
-					$progeny += 'link' == $type ? $child->link_count : $child->category_count;
+					if ( $child->{'link' == $type ? 'link_count' : 'category_count'} )
+						continue 2;
+
+				// It really is empty
+				unset($categories[$k]);
 			}
-			if ( !$progeny && $hide_empty )
-				unset($categories[$k]);
-			else
-				$categories[$k]->{'link' == $type ? 'link_count' : 'category_count'} = $progeny;
 		}
 	}
 	reset ( $categories );
@@ -130,6 +134,45 @@
 	return apply_filters('get_categories', $categories, $r);
 }
 
+// Recalculates link or post counts by including items from child categories
+// Assumes all relevant children are already in the $categories argument
+function pad_category_counts($type, &$categories) {
+	global $wpdb;
+
+	// Set up some useful arrays
+	foreach ( $categories as $key => $cat ) {
+		$cats[$cat->cat_ID] = & $categories[$key];
+		$cat_IDs[] = $cat->cat_ID;
+	}
+
+	// Get the relevant post2cat or link2cat records and stick them in a lookup table
+	if ( $type == 'post' ) {
+		$results = $wpdb->get_results("SELECT post_id, category_id FROM $wpdb->post2cat LEFT JOIN $wpdb->posts ON post_id = ID WHERE category_id IN (".join(',', $cat_IDs).") AND post_type = 'post' AND post_status = 'publish'");
+		foreach ( $results as $row )
+			++$cat_items[$row->category_id][$row->post_id];
+	} else {
+		$results = $wpdb->get_results($q="SELECT $wpdb->link2cat.link_id, category_id FROM $wpdb->link2cat LEFT JOIN $wpdb->links USING (link_id) WHERE category_id IN (".join(',', $cat_IDs).") AND link_visible = 'Y'");echo $q;
+		foreach ( $results as $row )
+			++$cat_items[$row->category_id][$row->link_id];
+	}
+
+	// Touch every ancestor's lookup row for each post in each category
+	foreach ( $cat_IDs as $cat_ID ) {
+		$child = $cat_ID;
+		while ( $parent = $cats[$child]->category_parent ) {
+			if ( !empty($cat_items[$cat_ID]) )
+				foreach ( $cat_items[$cat_ID] as $item_id => $touches )
+					++$cat_items[$parent][$item_id];
+			$child = $parent;
+		}
+	}
+
+	// Transfer the touched cells 
+	foreach ( $cat_items as $id => $items )
+		if ( isset($cats[$id]) )
+			$cats[$id]->{'link' == $type ? 'link_count' : 'category_count'} = count($items);
+}
+
 // Retrieves category data given a category ID or category object.
 // Handles category caching.
 function &get_category(&$category, $output = OBJECT) {
Index: wp-includes/category-template.php
===================================================================
--- wp-includes/category-template.php	(revision 4644)
+++ wp-includes/category-template.php	(working copy)
@@ -221,6 +221,8 @@
 		'child_of' => 0, 'feed' => '', 'feed_image' => '', 'exclude' => '',
 		'hierarchical' => true, 'title_li' => __('Categories'));
 	$r = array_merge($defaults, $r);
+	if ( !isset($r['pad_counts']) && $r['show_count'] && $r['hierarchical'] )
+		$r['pad_counts'] = true;
 	if ( isset($r['show_date']) )
 		$r['include_last_update_time'] = $r['show_date'];
 	extract($r);
Index: wp-content/themes/default/sidebar.php
===================================================================
--- wp-content/themes/default/sidebar.php	(revision 4644)
+++ wp-content/themes/default/sidebar.php	(working copy)
@@ -46,7 +46,7 @@
 				</ul>
 			</li>
 
-			<?php wp_list_categories('optioncount=1&title_li=<h2>Categories</h2>'); ?>
+			<?php wp_list_categories('show_count=1&title_li=<h2>Categories</h2>'); ?>
 
 			<?php /* If this is the frontpage */ if ( is_home() || is_page() ) { ?>
 				<?php wp_list_bookmarks(); ?>
