Support checksums for classes with non-ascii names.

Bug: 146597396
Change-Id: I1b677348720e58e2e4f142e79143581d84a9cb8c
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 7ba04b5..993363c 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -49,8 +49,8 @@
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ObjectArrays;
-import it.unimi.dsi.fastutil.objects.Object2LongMap;
-import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Reference2LongMap;
+import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -204,14 +204,15 @@
    */
   private void encodeChecksums(Iterable<VirtualFile> files) {
     List<DexProgramClass> classes = application.classes();
-    Object2LongMap<String> inputChecksums = new Object2LongOpenHashMap<>(classes.size());
+    Reference2LongMap<DexString> inputChecksums = new Reference2LongOpenHashMap<>(classes.size());
     for (DexProgramClass clazz : classes) {
-      inputChecksums.put(clazz.getType().descriptor.toASCIIString(), clazz.getChecksum());
+      inputChecksums.put(clazz.getType().descriptor, clazz.getChecksum());
     }
     for (VirtualFile file : files) {
       ClassesChecksum toWrite = new ClassesChecksum();
-      for (String desc : file.getClassDescriptors()) {
-        toWrite.addChecksum(desc, inputChecksums.getLong(desc));
+      for (DexProgramClass clazz : file.classes()) {
+        DexString desc = clazz.type.descriptor;
+        toWrite.addChecksum(desc.toString(), inputChecksums.getLong(desc));
       }
       file.injectString(application.dexItemFactory.createString(toWrite.toJsonString()));
     }
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index d5e338e..c69d8e0 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -716,7 +716,7 @@
 
       Long checksum = null;
       if (checksums != null && !checksums.isEmpty()) {
-        String desc = type.descriptor.toASCIIString();
+        String desc = type.toDescriptorString();
         checksum = checksums.getOrDefault(desc, null);
         if (!options.dexClassChecksumFilter.test(desc, checksum)) {
           continue;
diff --git a/src/test/java/com/android/tools/r8/dexfilemerger/NonAsciiClassNameChecksumTest.java b/src/test/java/com/android/tools/r8/dexfilemerger/NonAsciiClassNameChecksumTest.java
new file mode 100644
index 0000000..146c94f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/dexfilemerger/NonAsciiClassNameChecksumTest.java
@@ -0,0 +1,82 @@
+// Copyright (c) 2020, 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 com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+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 NonAsciiClassNameChecksumTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("Hello, world");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  public NonAsciiClassNameChecksumTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    Path intermediate1 = compileIntermediate(TæstClass.class);
+    Path intermediate2 = compileIntermediate(TestClåss.class);
+    testForD8()
+        .addProgramFiles(intermediate1, intermediate2)
+        .setMinApi(parameters.getApiLevel())
+        .setIncludeClassesChecksum(true)
+        .run(parameters.getRuntime(), TæstClass.class)
+        .assertSuccessWithOutput(EXPECTED)
+        .inspect(inspector -> {
+          checkIncludesChecksum(inspector, TæstClass.class);
+          checkIncludesChecksum(inspector, TestClåss.class);
+        });
+  }
+
+  private Path compileIntermediate(Class<?> clazz) throws Exception {
+    return testForD8()
+        .setOutputMode(OutputMode.DexFilePerClassFile)
+        .addProgramClasses(clazz)
+        .setMinApi(parameters.getApiLevel())
+        .setIncludeClassesChecksum(true)
+        .compile()
+        .inspect(inspector -> checkIncludesChecksum(inspector, clazz))
+        .writeToZip();
+  }
+
+  private void checkIncludesChecksum(CodeInspector inspector, Class<?> clazz) {
+    ClassSubject classSubject = inspector.clazz(clazz);
+    assertThat(classSubject, isPresent());
+    assertTrue(classSubject.getDexClass().asProgramClass().getChecksum() > 0);
+  }
+
+  static class TæstClass {
+    public static void main(String[] args) {
+      new TestClåss().foo();
+    }
+  }
+
+  static class TestClåss {
+    public void foo() {
+      System.out.println("Hello, world");
+    }
+  }
+}
\ No newline at end of file