Always initialize and write checksum encodings when requested.

Bug: 143949125
Change-Id: I76adc256039b156e7d77d6ddea1347004f7ad2b6
diff --git a/src/main/java/com/android/tools/r8/dex/ClassesChecksum.java b/src/main/java/com/android/tools/r8/dex/ClassesChecksum.java
index eaff74e..ffdb9a4 100644
--- a/src/main/java/com/android/tools/r8/dex/ClassesChecksum.java
+++ b/src/main/java/com/android/tools/r8/dex/ClassesChecksum.java
@@ -18,7 +18,7 @@
   private static final char PREFIX_CHAR1 = '~';
   private static final char PREFIX_CHAR2 = '~';
 
-  private Object2LongMap<String> dictionary = null;
+  private final Object2LongMap<String> dictionary = new Object2LongOpenHashMap<>();
 
   public ClassesChecksum() {
     assert PREFIX.length() == 3;
@@ -27,14 +27,7 @@
     assert PREFIX.charAt(2) == PREFIX_CHAR2;
   }
 
-  private void ensureMap() {
-    if (dictionary == null) {
-      dictionary = new Object2LongOpenHashMap<>();
-    }
-  }
-
   private void append(JsonObject json) {
-    ensureMap();
     json.entrySet()
         .forEach(
             entry ->
@@ -42,7 +35,6 @@
   }
 
   public void addChecksum(String classDescriptor, long crc) {
-    ensureMap();
     dictionary.put(classDescriptor, crc);
   }
 
diff --git a/src/test/java/com/android/tools/r8/dexfilemerger/DexMergeChecksumsFileWithNoClassesTest.java b/src/test/java/com/android/tools/r8/dexfilemerger/DexMergeChecksumsFileWithNoClassesTest.java
new file mode 100644
index 0000000..57fe4b3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/dexfilemerger/DexMergeChecksumsFileWithNoClassesTest.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.dexfilemerger;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DexMergeChecksumsFileWithNoClassesTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  public DexMergeChecksumsFileWithNoClassesTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testChecksumWithNoClasses() throws Exception {
+    Path out1 =
+        testForD8()
+            .setMinApi(parameters.getApiLevel())
+            .setMode(CompilationMode.DEBUG)
+            .setIncludeClassesChecksum(true)
+            .setIntermediate(true)
+            .compile()
+            .inspect(this::checkContainsChecksums)
+            .writeToZip();
+
+    Path out2 =
+        testForD8()
+            .setMinApi(parameters.getApiLevel())
+            .setMode(CompilationMode.DEBUG)
+            .setIncludeClassesChecksum(true)
+            .addProgramClasses(TestClass.class)
+            .setIntermediate(true)
+            .compile()
+            .inspect(this::checkContainsChecksums)
+            .writeToZip();
+
+    testForD8()
+        .addProgramFiles(out1, out2)
+        .setIncludeClassesChecksum(true)
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), TestClass.class)
+        .inspect(this::checkContainsChecksums);
+  }
+
+  private void checkContainsChecksums(CodeInspector inspector) {
+    inspector.getMarkers().forEach(m -> assertTrue(m.getHasChecksums()));
+    // It may be prudent to check that the dex file also has the encoding string, but that is
+    // not easily accessed.
+    inspector.allClasses().forEach(c -> c.getDexClass().asProgramClass().getChecksum());
+  }
+
+  public static class TestClass {
+
+    public static void main(String[] args) {
+      System.out.println("Hello world!");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 2a91e4b..2bc1dd4 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.cf.code.CfTryCatch;
 import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.dex.Marker;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
@@ -48,6 +49,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -391,6 +393,10 @@
     }
   }
 
+  public Collection<Marker> getMarkers() {
+    return dexItemFactory.extractMarkers();
+  }
+
   // Build the generic signature using the current mapping if any.
   class GenericSignatureGenerator implements GenericSignatureAction<String> {