Account for synthetic arguments of enum class initializer
  when collecting non-null param hints.

Bug: 121221542
Change-Id: I115d4141f37d207fa0cc4129f46146df2f3d12d4
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 5a4b204..f69251b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -321,6 +321,10 @@
     return accessFlags.isInterface();
   }
 
+  public boolean isEnum() {
+    return accessFlags.isEnum();
+  }
+
   public abstract void addDependencies(MixedSectionCollection collector);
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
index d15ed5a..4f79660 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
@@ -6,6 +6,7 @@
 
 import static kotlinx.metadata.Flag.Property.IS_VAR;
 
+import com.android.tools.r8.graph.DexClass;
 import kotlinx.metadata.KmClassVisitor;
 import kotlinx.metadata.KmConstructorVisitor;
 import kotlinx.metadata.KmFunctionVisitor;
@@ -14,14 +15,15 @@
 
 public class KotlinClass extends KotlinInfo<KotlinClassMetadata.Class> {
 
-  static KotlinClass fromKotlinClassMetadata(KotlinClassMetadata kotlinClassMetadata) {
+  static KotlinClass fromKotlinClassMetadata(
+      KotlinClassMetadata kotlinClassMetadata, DexClass clazz) {
     assert kotlinClassMetadata instanceof KotlinClassMetadata.Class;
     KotlinClassMetadata.Class kClass = (KotlinClassMetadata.Class) kotlinClassMetadata;
-    return new KotlinClass(kClass);
+    return new KotlinClass(kClass, clazz);
   }
 
-  private KotlinClass(KotlinClassMetadata.Class metadata) {
-    super(metadata);
+  private KotlinClass(KotlinClassMetadata.Class metadata, DexClass clazz) {
+    super(metadata, clazz);
   }
 
   @Override
@@ -38,7 +40,7 @@
 
     @Override
     public KmConstructorVisitor visitConstructor(int ctorFlags) {
-      return new NonNullParameterHintCollector.ConstructorVisitor(nonNullparamHints);
+      return new NonNullParameterHintCollector.ConstructorVisitor(nonNullparamHints, clazz);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index 6518bb8..6004201 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -77,7 +77,7 @@
     KotlinClassMetadata kMetadata = KotlinClassMetadata.read(header);
 
     if (kMetadata instanceof KotlinClassMetadata.Class) {
-      return KotlinClass.fromKotlinClassMetadata(kMetadata);
+      return KotlinClass.fromKotlinClassMetadata(kMetadata, clazz);
     } else if (kMetadata instanceof KotlinClassMetadata.FileFacade) {
       return KotlinFile.fromKotlinClassMetadata(kMetadata);
     } else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassFacade) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
index 7cc8aa1..ef90173 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin;
 
+import com.android.tools.r8.graph.DexClass;
 import com.google.common.collect.HashBasedTable;
 import java.util.BitSet;
 import kotlinx.metadata.jvm.KotlinClassMetadata;
@@ -11,12 +12,18 @@
 // Provides access to kotlin information.
 public abstract class KotlinInfo<MetadataKind extends KotlinClassMetadata> {
   MetadataKind metadata;
+  DexClass clazz;
   final HashBasedTable<String, String, BitSet> nonNullparamHints = HashBasedTable.create();
 
   KotlinInfo() {
   }
 
   KotlinInfo(MetadataKind metadata) {
+    this(metadata, null);
+  }
+
+  KotlinInfo(MetadataKind metadata, DexClass clazz) {
+    this.clazz = clazz;
     processMetadata(metadata);
     this.metadata = metadata;
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/NonNullParameterHintCollector.java b/src/main/java/com/android/tools/r8/kotlin/NonNullParameterHintCollector.java
index 20621f9..079980f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/NonNullParameterHintCollector.java
+++ b/src/main/java/com/android/tools/r8/kotlin/NonNullParameterHintCollector.java
@@ -6,6 +6,7 @@
 
 import static kotlinx.metadata.Flag.Type.IS_NULLABLE;
 
+import com.android.tools.r8.graph.DexClass;
 import com.google.common.collect.HashBasedTable;
 import java.util.BitSet;
 import kotlinx.metadata.KmConstructorExtensionVisitor;
@@ -94,8 +95,18 @@
     private final String name = "<init>";
     private String descriptor = "";
 
-    ConstructorVisitor(HashBasedTable<String, String, BitSet> paramHints) {
+    ConstructorVisitor(HashBasedTable<String, String, BitSet> paramHints, DexClass clazz) {
       this.paramHints = paramHints;
+      // Enum constructor has two synthetic arguments to java.lang.Enum's sole constructor:
+      // https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#Enum-java.lang.String-int-
+      // whereas Kotlin @Metadata is still based on constructor signature, not descriptor.
+      if (clazz != null && clazz.isEnum()) {
+        // name - The name of this enum constant, which is the identifier used to declare it.
+        paramIndex++;
+        // ordinal - The ordinal of this enumeration constant (its position in the enum declaration,
+        // where the initial constant is assigned an ordinal of zero).
+        paramIndex++;
+      }
     }
 
     @Override
diff --git a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
new file mode 100644
index 0000000..179f9c6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2018, 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.naming;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.Streams;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class EnumMinificationKotlinTest extends KotlinTestBase {
+  private static final String FOLDER = "minify_enum";
+  private static final String MAIN_CLASS_NAME = "minify_enum.MainKt";
+  private static final String ENUM_CLASS_NAME = "minify_enum.MinifyEnum";
+
+  private final Backend backend;
+  private final boolean minify;
+
+  @Parameterized.Parameters(name = "Backend: {0} target: {1} minify: {2}")
+  public static Collection<Object[]> data() {
+    return buildParameters(Backend.values(), KotlinTargetVersion.values(), BooleanUtils.values());
+  }
+
+  public EnumMinificationKotlinTest(
+      Backend backend, KotlinTargetVersion targetVersion, boolean minify) {
+    super(targetVersion);
+    this.backend = backend;
+    this.minify = minify;
+  }
+
+  @Test
+  public void b121221542() throws Exception {
+    R8TestBuilder builder = testForR8(backend)
+        .addProgramFiles(getKotlinJarFile(FOLDER))
+        .addProgramFiles(getJavaJarFile(FOLDER))
+        .addKeepMainRule(MAIN_CLASS_NAME);
+    if (!minify) {
+      builder.noMinification();
+    }
+    CodeInspector inspector = builder.run(MAIN_CLASS_NAME).inspector();
+    ClassSubject enumClass = inspector.clazz(ENUM_CLASS_NAME);
+    assertThat(enumClass, isPresent());
+    assertEquals(minify, enumClass.isRenamed());
+    MethodSubject clinit = enumClass.clinit();
+    assertThat(clinit, isPresent());
+    assertEquals(0,
+        Streams.stream(clinit.iterateInstructions(InstructionSubject::isThrow)).count());
+  }
+
+}
diff --git a/src/test/kotlinR8TestResources/minify_enum/main.kt b/src/test/kotlinR8TestResources/minify_enum/main.kt
new file mode 100644
index 0000000..d35ecf5
--- /dev/null
+++ b/src/test/kotlinR8TestResources/minify_enum/main.kt
@@ -0,0 +1,16 @@
+// Copyright (c) 2018, 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 minify_enum
+
+enum class MinifyEnum(
+    val nullableStr1: String?,
+    val nullableStr2: String?,
+    val number3: String
+) {
+  UNKNOWN(null, null, "")
+}
+
+fun main(args: Array<String>) {
+  val a = MinifyEnum.UNKNOWN
+}