Improve the output of the diff tool (#45)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a821d69..f1bc876 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.5.12
+
+* Improved output of `dart2js_info_diff` by sorting the diffs by
+  size and outputting the summary in full output mode.
+
 ## 0.5.11
 
 * Added `--summary` option to `dart2js_info_diff` tool.
diff --git a/README.md b/README.md
index cc9df90..385ceb7 100644
--- a/README.md
+++ b/README.md
@@ -141,28 +141,64 @@
 Here's an example output:
 
 ```
-OVERALL SIZE DIFFERENCE
-========================================================================
-3 bytes
+total_size_difference -2688
+total_added 0
+total_removed 2321
+total_size_changed -203
+total_became_deferred 0
+total_no_longer_deferred 0
 
-ADDED
+ADDED (0 bytes)
 ========================================================================
 
-REMOVED
+REMOVED (2321 bytes)
 ========================================================================
-file:///home/het/Code/foo/foo.dart::A.y: 0 bytes
+dart:_js_helper::getRuntimeTypeString: 488 bytes
+dart:_js_helper::substitute: 479 bytes
+dart:_js_helper::TypeImpl.toString: 421 bytes
+dart:_js_helper::computeSignature: 204 bytes
+dart:_js_helper::getRuntimeTypeArguments: 181 bytes
+dart:_js_helper::extractFunctionTypeObjectFrom: 171 bytes
+dart:_js_helper::getTypeArgumentByIndex: 147 bytes
+dart:_js_helper::runtimeTypeToString: 136 bytes
+dart:_js_helper::setRuntimeTypeInfo: 94 bytes
+dart:core::Object.runtimeType: 0 bytes
+dart:_js_helper::getRawRuntimeType: 0 bytes
+dart:_js_helper::invoke: 0 bytes
+dart:_js_helper::invokeOn: 0 bytes
+dart:_js_helper::getField: 0 bytes
+dart:_js_helper::getClassName: 0 bytes
+dart:_js_helper::getRuntimeType: 0 bytes
+dart:_js_helper::TypeImpl.TypeImpl: 0 bytes
 
-CHANGED SIZE
+CHANGED SIZE (-203 bytes)
+========================================================================
+dart:_interceptors::JSUnmodifiableArray: -3 bytes
+dart:core::List: -3 bytes
+dart:_interceptors::ArrayIterator: -4 bytes
+dart:_js_helper::TypeImpl._typeName: -10 bytes
+dart:_js_helper::TypeImpl._unmangledName: -15 bytes
+dart:_js_names::: -30 bytes
+dart:_js_names::extractKeys: -30 bytes
+dart:core::StringBuffer: -40 bytes
+dart:core::StringBuffer._writeAll: -40 bytes
+dart:core::: -43 bytes
+dart:_interceptors::JSArray.+: -63 bytes
+dart:_interceptors::JSArray: -66 bytes
+dart:_interceptors::: -73 bytes
+dart:_js_helper::TypeImpl: -481 bytes
+dart:_js_helper::: -2445 bytes
+
+BECAME DEFERRED (0 bytes)
 ========================================================================
 
-BECAME DEFERRED
-========================================================================
-
-NO LONGER DEFERRED
+NO LONGER DEFERRED (0 bytes)
 ========================================================================
 
 ```
 
+You can also pass `--summary` to only show the summary section.
+
 ### Library size split tool
 
 This command-line tool shows the size distribution of generated code among
diff --git a/bin/diff.dart b/bin/diff.dart
index 2bac65e..8be1dd3 100644
--- a/bin/diff.dart
+++ b/bin/diff.dart
@@ -56,12 +56,48 @@
     }
   }
 
-  if (summary) {
-    reportSummary(oldInfo, newInfo, adds, removals, sizeChanges, becameDeferred,
-        becameUndeferred);
-  } else {
+  // Sort the changes by the size of the element that changed.
+  for (var diffs in [adds, removals, becameDeferred, becameUndeferred]) {
+    diffs.sort((a, b) => b.info.size - a.info.size);
+  }
+
+  // Sort changes in size by size difference.
+  sizeChanges.sort((a, b) => b.sizeDifference - a.sizeDifference);
+
+  var totalSizes = <List<Diff>, int>{};
+  for (var diffs in [adds, removals, becameDeferred, becameUndeferred]) {
+    var totalSize = 0;
+    for (var diff in diffs) {
+      // Only count diffs from leaf elements so we don't double count
+      // them when we account for class size diff or library size diff.
+      if (diff.info.kind == InfoKind.field ||
+          diff.info.kind == InfoKind.function ||
+          diff.info.kind == InfoKind.closure ||
+          diff.info.kind == InfoKind.typedef) {
+        totalSize += diff.info.size;
+      }
+    }
+    totalSizes[diffs] = totalSize;
+  }
+  var totalSizeChange = 0;
+  for (var sizeChange in sizeChanges) {
+    // Only count diffs from leaf elements so we don't double count
+    // them when we account for class size diff or library size diff.
+    if (sizeChange.info.kind == InfoKind.field ||
+        sizeChange.info.kind == InfoKind.function ||
+        sizeChange.info.kind == InfoKind.closure ||
+        sizeChange.info.kind == InfoKind.typedef) {
+      totalSizeChange += sizeChange.sizeDifference;
+    }
+  }
+  totalSizes[sizeChanges] = totalSizeChange;
+
+  reportSummary(oldInfo, newInfo, adds, removals, sizeChanges, becameDeferred,
+      becameUndeferred, totalSizes);
+  if (!summary) {
+    print('');
     reportFull(oldInfo, newInfo, adds, removals, sizeChanges, becameDeferred,
-        becameUndeferred);
+        becameUndeferred, totalSizes);
   }
 }
 
@@ -72,27 +108,16 @@
     List<RemoveDiff> removals,
     List<SizeDiff> sizeChanges,
     List<DeferredStatusDiff> becameDeferred,
-    List<DeferredStatusDiff> becameUndeferred) {
+    List<DeferredStatusDiff> becameUndeferred,
+    Map<List<Diff>, int> totalSizes) {
   var overallSizeDiff = newInfo.program.size - oldInfo.program.size;
   print('total_size_difference $overallSizeDiff');
 
-  var noLongerDeferred = 0;
-  for (var diff in becameUndeferred) {
-    noLongerDeferred += diff.info.size;
-  }
-  print('no_longer_deferred $noLongerDeferred');
-
-  var totalAdded = 0;
-  for (var diff in adds) {
-    totalAdded += diff.info.size;
-  }
-  print('total_added $totalAdded');
-
-  var totalRemoved = 0;
-  for (var diff in removals) {
-    totalRemoved += diff.info.size;
-  }
-  print('total_removed $totalRemoved');
+  print('total_added ${totalSizes[adds]}');
+  print('total_removed ${totalSizes[removals]}');
+  print('total_size_changed ${totalSizes[sizeChanges]}');
+  print('total_became_deferred ${totalSizes[becameDeferred]}');
+  print('total_no_longer_deferred ${totalSizes[becameUndeferred]}');
 }
 
 void reportFull(
@@ -102,49 +127,46 @@
     List<RemoveDiff> removals,
     List<SizeDiff> sizeChanges,
     List<DeferredStatusDiff> becameDeferred,
-    List<DeferredStatusDiff> becameUndeferred) {
+    List<DeferredStatusDiff> becameUndeferred,
+    Map<List<Diff>, int> totalSizes) {
   // TODO(het): Improve this output. Siggi has good suggestions in
   // https://github.com/dart-lang/dart2js_info/pull/19
-  var overallSizeDiff = newInfo.program.size - oldInfo.program.size;
-  _section('OVERALL SIZE DIFFERENCE');
-  print('$overallSizeDiff bytes');
-  print('');
 
-  _section('ADDED');
+  _section('ADDED', size: totalSizes[adds]);
   for (var add in adds) {
     print('${longName(add.info, useLibraryUri: true)}: ${add.info.size} bytes');
   }
   print('');
 
-  _section('REMOVED');
+  _section('REMOVED', size: totalSizes[removals]);
   for (var removal in removals) {
     print('${longName(removal.info, useLibraryUri: true)}: '
         '${removal.info.size} bytes');
   }
   print('');
 
-  _section('CHANGED SIZE');
+  _section('CHANGED SIZE', size: totalSizes[sizeChanges]);
   for (var sizeChange in sizeChanges) {
     print('${longName(sizeChange.info, useLibraryUri: true)}: '
         '${sizeChange.sizeDifference} bytes');
   }
   print('');
 
-  _section('BECAME DEFERRED');
+  _section('BECAME DEFERRED', size: totalSizes[becameDeferred]);
   for (var diff in becameDeferred) {
     print('${longName(diff.info, useLibraryUri: true)}: '
         '${diff.info.size} bytes');
   }
   print('');
 
-  _section('NO LONGER DEFERRED');
+  _section('NO LONGER DEFERRED', size: totalSizes[becameUndeferred]);
   for (var diff in becameUndeferred) {
     print('${longName(diff.info, useLibraryUri: true)}: '
         '${diff.info.size} bytes');
   }
 }
 
-void _section(String title) {
-  print(title);
+void _section(String title, {int size}) {
+  print('$title ($size bytes)');
   print('=' * 72);
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index 636e370..48cc510 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: dart2js_info
-version: 0.5.11
+version: 0.5.12
 
 description: >
   Libraries and tools to process data produced when running dart2js with