Fix overflow in R8 stats metadata

Fixes: b/436805211
Change-Id: I66af37e7c3998597f0317d3736815c210dbe79b4
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index fee3104..36c3a0a 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -48,6 +48,7 @@
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.metadata.impl.BuildMetadataFactory;
+import com.android.tools.r8.metadata.impl.R8StatsMetadataImpl;
 import com.android.tools.r8.naming.KotlinModuleSynthesizer;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
@@ -723,6 +724,8 @@
       assert appView.hasClassHierarchy();
       options.r8BuildMetadataConsumer.accept(
           BuildMetadataFactory.create(appView.withClassHierarchy(), virtualFiles));
+    } else if (appView.hasClassHierarchy()) {
+      assert R8StatsMetadataImpl.Counters.create(appView.withClassHierarchy()).validate();
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/metadata/impl/R8StatsMetadataImpl.java b/src/main/java/com/android/tools/r8/metadata/impl/R8StatsMetadataImpl.java
index 05b8e2f..4928feb 100644
--- a/src/main/java/com/android/tools/r8/metadata/impl/R8StatsMetadataImpl.java
+++ b/src/main/java/com/android/tools/r8/metadata/impl/R8StatsMetadataImpl.java
@@ -70,7 +70,7 @@
     return noShrinkingPercentage;
   }
 
-  private static class Counters {
+  public static class Counters {
 
     private int itemsCount = 0;
     private int noObfuscationCount = 0;
@@ -79,12 +79,13 @@
 
     private Counters() {}
 
-    static Counters create(AppView<? extends AppInfoWithClassHierarchy> appView) {
+    public static Counters create(AppView<? extends AppInfoWithClassHierarchy> appView) {
       Counters counters = new Counters();
       for (DexProgramClass clazz : appView.appInfo().classes()) {
         counters.add(appView, clazz);
         clazz.forEachProgramMember(member -> counters.add(appView, member));
       }
+      assert counters.validate();
       return counters;
     }
 
@@ -111,9 +112,34 @@
     }
 
     float toPercentageWithTwoDecimals(int count) {
-      // Multiply by 100 twice to get percentage with two decimals.
-      float number = (float) (count * 100 * 100) / itemsCount;
-      return (float) Math.round(number) / 100;
+      if (itemsCount == 0) {
+        return 0f;
+      }
+      float fraction = (float) count / itemsCount;
+      assert verifyValidFraction(fraction);
+      float percentage = fraction * 100;
+      assert verifyValidPercentage(percentage);
+      // Multiply and divide by 100 to get percentage with two decimals.
+      return (float) Math.round(percentage * 100) / 100;
+    }
+
+    public boolean validate() {
+      assert verifyValidPercentage(getNoObfuscationPercentage());
+      assert verifyValidPercentage(getNoOptimizationPercentage());
+      assert verifyValidPercentage(getNoShrinkingPercentage());
+      return true;
+    }
+
+    private boolean verifyValidFraction(float f) {
+      assert 0f <= f;
+      assert f <= 1f;
+      return true;
+    }
+
+    private boolean verifyValidPercentage(float f) {
+      assert 0f <= f;
+      assert f <= 100f;
+      return true;
     }
   }
 }