Add an option to "force Proguard compatibility"

Right now it will keep the default constructor for all live classes.

Only available through from the CompatProguard command.

Change-Id: Ic5e9b515973bf6e89eb783ab2f91665a5583a4c8
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 296507f..a885bbb 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -42,7 +42,8 @@
     AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
     RootSet mainDexRootSet =
         new RootSetBuilder(application, appInfo, options.mainDexKeepRules, options).run(executor);
-    Set<DexType> mainDexBaseClasses = new Enqueuer(appInfo).traceMainDex(mainDexRootSet, timing);
+    Set<DexType> mainDexBaseClasses =
+        new Enqueuer(appInfo, options).traceMainDex(mainDexRootSet, timing);
     Set<DexType> mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, application).run();
 
     List<String> result = mainDexClasses.stream()
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 39e0342..cbb7f0b 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -221,7 +221,7 @@
             new RootSetBuilder(
                     application, appInfo, options.proguardConfiguration.getRules(), options)
                 .run(executorService);
-        Enqueuer enqueuer = new Enqueuer(appInfo);
+        Enqueuer enqueuer = new Enqueuer(appInfo, options);
         enqueuer.addExtension(new ProtoLiteExtension(appInfo));
         appInfo = enqueuer.traceApplication(rootSet, timing);
         if (options.proguardConfiguration.isPrintSeeds()) {
@@ -282,7 +282,7 @@
 
       if (!options.mainDexKeepRules.isEmpty()) {
         appInfo = new AppInfoWithSubtyping(application);
-        Enqueuer enqueuer = new Enqueuer(appInfo);
+        Enqueuer enqueuer = new Enqueuer(appInfo, options);
         // Lets find classes which may have code executed before secondary dex files installation.
         RootSet mainDexRootSet =
             new RootSetBuilder(application, appInfo, options.mainDexKeepRules, options)
@@ -301,7 +301,7 @@
       if (options.useTreeShaking || !options.skipMinification) {
         timing.begin("Post optimization code stripping");
         try {
-          Enqueuer enqueuer = new Enqueuer(appInfo);
+          Enqueuer enqueuer = new Enqueuer(appInfo, options);
           appInfo = enqueuer.traceApplication(rootSet, timing);
           if (options.useTreeShaking) {
             TreePruner pruner = new TreePruner(application, appInfo.withLiveness(), options);
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 502dd3c..9529093 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -36,12 +36,18 @@
     private Optional<Boolean> discardedChecker = Optional.empty();
     private Optional<Boolean> minification = Optional.empty();
     private boolean ignoreMissingClasses = false;
+    private boolean forceProguardCompatibility = false;
     private Path proguardMapOutput = null;
 
     private Builder() {
       super(CompilationMode.RELEASE);
     }
 
+    protected Builder(boolean forceProguardCompatibility) {
+      super(CompilationMode.RELEASE);
+      this.forceProguardCompatibility = forceProguardCompatibility;
+    }
+
     private Builder(AndroidApp app) {
       super(app, CompilationMode.RELEASE);
     }
@@ -243,6 +249,7 @@
           useDiscardedChecker,
           useMinification,
           ignoreMissingClasses,
+          forceProguardCompatibility,
           proguardMapOutput);
     }
   }
@@ -283,6 +290,7 @@
   private final boolean useDiscardedChecker;
   private final boolean useMinification;
   private final boolean ignoreMissingClasses;
+  private final boolean forceProguardCompatibility;
   private final Path proguardMapOutput;
 
   public static Builder builder() {
@@ -400,6 +408,7 @@
       boolean useDiscardedChecker,
       boolean useMinification,
       boolean ignoreMissingClasses,
+      boolean forceProguardCompatibility,
       Path proguardMapOutput) {
     super(inputApp, outputPath, outputMode, mode, minApiLevel, diagnosticsHandler,
         enableDesugaring);
@@ -413,6 +422,7 @@
     this.useDiscardedChecker = useDiscardedChecker;
     this.useMinification = useMinification;
     this.ignoreMissingClasses = ignoreMissingClasses;
+    this.forceProguardCompatibility = forceProguardCompatibility;
     this.proguardMapOutput = proguardMapOutput;
   }
 
@@ -425,6 +435,7 @@
     useDiscardedChecker = false;
     useMinification = false;
     ignoreMissingClasses = false;
+    forceProguardCompatibility = false;
     proguardMapOutput = null;
   }
   public boolean useTreeShaking() {
@@ -477,6 +488,11 @@
       internal.inlineAccessors = false;
     }
     internal.proguardMapOutput = proguardMapOutput;
+
+    // EXPERIMENTAL flags.
+    assert !internal.forceProguardCompatibility;
+    internal.forceProguardCompatibility = forceProguardCompatibility;
+
     return internal;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/ConstClass.java b/src/main/java/com/android/tools/r8/code/ConstClass.java
index 04fda4b..a5755e9 100644
--- a/src/main/java/com/android/tools/r8/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/code/ConstClass.java
@@ -36,7 +36,7 @@
 
   @Override
   public void registerUse(UseRegistry registry) {
-    registry.registerTypeReference(getType());
+    registry.registerConstClass(getType());
   }
 
   public DexType getType() {
diff --git a/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java b/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
index 1ad589f..9dc5424 100644
--- a/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
+++ b/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
@@ -26,17 +26,21 @@
   public static class CompatProguardOptions {
     public final String output;
     public final int minApi;
+    public final boolean forceProguardCompatibility;
     public final List<String> proguardConfig;
 
-    CompatProguardOptions(List<String> proguardConfig, String output, int minApi) {
+    CompatProguardOptions(List<String> proguardConfig, String output, int minApi,
+        boolean forceProguardCompatibility) {
       this.output = output;
       this.minApi = minApi;
+      this.forceProguardCompatibility = forceProguardCompatibility;
       this.proguardConfig = proguardConfig;
     }
 
     public static CompatProguardOptions parse(String[] args) throws CompilationException {
       String output = null;
       int minApi = 1;
+      boolean forceProguardCompatibility = false;
       ImmutableList.Builder<String> builder = ImmutableList.builder();
       if (args.length > 0) {
         StringBuilder currentLine = new StringBuilder(args[0]);
@@ -45,6 +49,8 @@
           if (arg.charAt(0) == '-') {
             if (arg.equals("--min-api")) {
               minApi = Integer.valueOf(args[++i]);
+            } else if (arg.equals("--force-proguard-compatibility")) {
+              forceProguardCompatibility = true;
             } else if (arg.equals("--output")) {
               output = args[++i];
             } else if (arg.equals("-outjars")) {
@@ -60,7 +66,7 @@
         }
         builder.add(currentLine.toString());
       }
-      return new CompatProguardOptions(builder.build(), output, minApi);
+      return new CompatProguardOptions(builder.build(), output, minApi, forceProguardCompatibility);
     }
   }
 
@@ -68,11 +74,12 @@
     System.out.println("CompatProguard " + String.join(" ", args));
     // Run R8 passing all the options from the command line as a Proguard configuration.
     CompatProguardOptions options = CompatProguardOptions.parse(args);
-    R8.run(R8Command.builder()
-        .setOutputPath(Paths.get(options.output))
+    R8Command.Builder builder =
+        new CompatProguardCommandBuilder(options.forceProguardCompatibility);
+    builder.setOutputPath(Paths.get(options.output))
         .addProguardConfiguration(options.proguardConfig)
-        .setMinApiLevel(options.minApi)
-        .build());
+        .setMinApiLevel(options.minApi);
+    R8.run(builder.build());
   }
 
   public static void main(String[] args) throws IOException {
diff --git a/src/main/java/com/android/tools/r8/compatproguard/CompatProguardCommandBuilder.java b/src/main/java/com/android/tools/r8/compatproguard/CompatProguardCommandBuilder.java
new file mode 100644
index 0000000..df2298c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/compatproguard/CompatProguardCommandBuilder.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2017, 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.compatproguard;
+
+import com.android.tools.r8.R8Command;
+
+public class CompatProguardCommandBuilder extends R8Command.Builder {
+  CompatProguardCommandBuilder(boolean forceProguardCompatibility) {
+    super(forceProguardCompatibility);
+  }
+}
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 5de6538..e454d89 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -239,6 +239,19 @@
     return true;
   }
 
+  public boolean hasDefaultInitializer() {
+    return getDefaultInitializer() != null;
+  }
+
+  public DexEncodedMethod getDefaultInitializer() {
+    for (DexEncodedMethod method : directMethods()) {
+      if (method.isDefaultInitializer()) {
+        return method;
+      }
+    }
+    return null;
+  }
+
   public boolean defaultValuesForStaticFieldsMayTriggerAllocation() {
     return Arrays.stream(staticFields())
         .anyMatch(field -> !field.staticValue.mayTriggerAllocation());
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 7766a94..a541f5a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -204,6 +204,10 @@
     return accessFlags.isConstructor() && !accessFlags.isStatic();
   }
 
+  public boolean isDefaultInitializer() {
+    return isInstanceInitializer() && method.proto.parameters.isEmpty();
+  }
+
   public boolean isClassInitializer() {
     return accessFlags.isConstructor() && accessFlags.isStatic();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index 78b2f56..f6736fa 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -65,4 +65,8 @@
         throw new AssertionError();
     }
   }
+
+  public boolean registerConstClass(DexType type) {
+    return registerTypeReference(type);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/jar/JarRegisterEffectsVisitor.java b/src/main/java/com/android/tools/r8/jar/JarRegisterEffectsVisitor.java
index c718e91..e1599b9 100644
--- a/src/main/java/com/android/tools/r8/jar/JarRegisterEffectsVisitor.java
+++ b/src/main/java/com/android/tools/r8/jar/JarRegisterEffectsVisitor.java
@@ -48,7 +48,7 @@
   @Override
   public void visitLdcInsn(Object cst) {
     if (cst instanceof Type) {
-      registry.registerTypeReference(application.getType((Type) cst));
+      registry.registerConstClass(application.getType((Type) cst));
     } else if (cst instanceof Handle) {
       registerMethodHandleType((Handle) cst);
     }
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
index 1537f05..762bdb6 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
+import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -280,6 +281,10 @@
           method.proto.returnType.toSourceString(), paramNames);
     }
 
+    public static MethodSignature initializer(String[] parameters) {
+      return new MethodSignature(Constants.INSTANCE_INITIALIZER_NAME, "void", parameters);
+    }
+
     @Override
     Signature asRenamed(String renamedName) {
       return new MethodSignature(renamedName, type, parameters);
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index ff8adee..358c1d3 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -28,6 +28,7 @@
 import com.android.tools.r8.graph.PresortedComparable;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.base.Equivalence.Wrapper;
@@ -69,6 +70,7 @@
 public class Enqueuer {
 
   private final AppInfoWithSubtyping appInfo;
+  private final InternalOptions options;
   private RootSet rootSet;
 
   private Map<DexType, Set<DexMethod>> virtualInvokes = Maps.newIdentityHashMap();
@@ -156,8 +158,9 @@
    */
   private final Map<DexType, Set<DexAnnotation>> deferredAnnotations = new IdentityHashMap<>();
 
-  public Enqueuer(AppInfoWithSubtyping appInfo) {
+  public Enqueuer(AppInfoWithSubtyping appInfo, InternalOptions options) {
     this.appInfo = appInfo;
+    this.options = options;
   }
 
   public void addExtension(SemanticsProvider extension) {
@@ -332,6 +335,30 @@
       }
       return false;
     }
+
+    @Override
+    public boolean registerConstClass(DexType type) {
+      boolean result = registerTypeReference(type);
+      // For Proguard compatibility mark default initializer for live type as live.
+      if (options.forceProguardCompatibility) {
+        if (type.isArrayType()) {
+          return result;
+        }
+        assert type.isClassType();
+        DexClass holder = appInfo.definitionFor(type);
+        if (holder == null) {
+          // Don't call reportMissingClass(type) here. That already happened in the call to
+          // registerTypeReference(type).
+          return result;
+        }
+        if (holder.hasDefaultInitializer()) {
+          registerNewInstance(type);
+          DexEncodedMethod init = holder.getDefaultInitializer();
+          markDirectStaticOrConstructorMethodAsLive(init, KeepReason.reachableFromLiveType(type));
+        }
+      }
+      return result;
+    }
   }
 
   //
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 947abe3..10716bd 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -76,7 +76,7 @@
       } else {
         newClasses.add(clazz);
         if (!appInfo.instantiatedTypes.contains(clazz.type) &&
-            (!options.debugKeepRules || !hasDefaultConstructor(clazz))) {
+            (!options.debugKeepRules || !clazz.hasDefaultInitializer())) {
           // The class is only needed as a type but never instantiated. Make it abstract to reflect
           // this.
           if (clazz.accessFlags.isFinal()) {
@@ -102,15 +102,6 @@
     return newClasses;
   }
 
-  private boolean hasDefaultConstructor(DexProgramClass clazz) {
-    for (DexEncodedMethod method : clazz.directMethods()) {
-      if (isDefaultConstructor(method)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
   private <S extends PresortedComparable<S>, T extends KeyedDexItem<S>> int firstUnreachableIndex(
       T[] items, Set<S> live) {
     for (int i = 0; i < items.length; i++) {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 68a6502..9f883bf 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -103,6 +103,8 @@
   public String printCfgFile;
   public Path printMainDexListFile;
   public boolean ignoreMissingClasses = false;
+  // EXPERIMENTAL flag to get behaviour as close to Proguard as possible.
+  public boolean forceProguardCompatibility = false;
   public boolean skipMinification = false;
   public boolean disableAssertions = true;
   public boolean debugKeepRules = false;
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index e46ff48..984d112 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.utils.OutputMode;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 import com.google.common.io.ByteStreams;
 import java.io.File;
 import java.io.FileInputStream;
@@ -92,6 +93,20 @@
   }
 
   /**
+   * Get the class name generated by javac.
+   */
+  protected String getJavacGeneratedClassName(Class clazz) {
+    List<String> parts = Lists.newArrayList(clazz.getCanonicalName().split("\\."));
+    Class enclosing = clazz;
+    while (enclosing.getEnclosingClass() != null) {
+      parts.set(parts.size() - 2, parts.get(parts.size() - 2) + "$" + parts.get(parts.size() - 1));
+      parts.remove(parts.size() - 1);
+      enclosing = clazz.getEnclosingClass();
+    }
+    return String.join(".", parts);
+  }
+
+  /**
    * Compile an application with D8.
    */
   protected AndroidApp compileWithD8(AndroidApp app)
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index 3d65e0d..53f0793 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -73,7 +73,7 @@
 
     RootSet rootSet = new RootSetBuilder(program, appInfo, configuration.getRules(), options)
         .run(ThreadUtils.getExecutorService(options));
-    Enqueuer enqueuer = new Enqueuer(appInfo);
+    Enqueuer enqueuer = new Enqueuer(appInfo, options);
     appInfo = enqueuer.traceApplication(rootSet, timing);
     return new Minifier(appInfo.withLiveness(), rootSet, options).run(timing);
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
new file mode 100644
index 0000000..4d59f63
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2017, 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.shaking.forceproguardcompatibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.DexInspector.ClassSubject;
+import com.android.tools.r8.utils.DexInspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class ForceProguardCompatibilityTest extends TestBase {
+  private void test(Class mainClass, Class mentionedClass, boolean arrayClass,
+      boolean forceProguardCompatibility)
+      throws Exception {
+    String proguardConfig = keepMainProguardConfiguration(mainClass, true, false);
+    DexInspector inspector = new DexInspector(
+        compileWithR8(
+            ImmutableList.of(mainClass, mentionedClass),
+            proguardConfig,
+            options -> options.forceProguardCompatibility = forceProguardCompatibility));
+    assertTrue(inspector.clazz(mainClass.getCanonicalName()).isPresent());
+    ClassSubject clazz = inspector.clazz(getJavacGeneratedClassName(mentionedClass));
+    assertTrue(clazz.isPresent());
+    if (arrayClass) {
+      MethodSubject defaultInitializer = clazz.method(MethodSignature.initializer(new String[]{}));
+      assertFalse(defaultInitializer.isPresent());
+    } else {
+      MethodSubject defaultInitializer = clazz.method(MethodSignature.initializer(new String[]{}));
+      assertEquals(forceProguardCompatibility, defaultInitializer.isPresent());
+    }
+  }
+
+  @Test
+  public void testKeepDefaultInitializer() throws Exception {
+    test(TestMain.class, TestMain.MentionedClass.class, false, true);
+    test(TestMain.class, TestMain.MentionedClass.class, false, false);
+  }
+
+  @Test
+  public void testKeepDefaultInitializerArrayType() throws Exception {
+    test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, true, true);
+    test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, true, false);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMain.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMain.java
new file mode 100644
index 0000000..94a9d0a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMain.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2017, 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.shaking.forceproguardcompatibility;
+
+public class TestMain {
+
+  public static class MentionedClass {
+    public MentionedClass() {
+    }
+  }
+
+  public static void main(String[] args) {
+    System.out.println(MentionedClass.class.getCanonicalName());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMainArrayType.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMainArrayType.java
new file mode 100644
index 0000000..8b1acaf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMainArrayType.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2017, 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.shaking.forceproguardcompatibility;
+
+public class TestMainArrayType {
+
+  public static class MentionedClass {
+    public MentionedClass() {
+    }
+  }
+
+  public static void main(String[] args) {
+    System.out.println(MentionedClass[].class.getCanonicalName());
+  }
+}