Merge "Make minification deterministic."
diff --git a/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java b/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
index ddb0244..5755c04 100644
--- a/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
+++ b/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
@@ -33,6 +33,10 @@
       "}"
   );
 
+  public CompatProguardCommandBuilder() {
+    this(true);
+  }
+
   public CompatProguardCommandBuilder(boolean forceProguardCompatibility) {
     super(forceProguardCompatibility);
     setIgnoreDexInArchive(true);
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index ddb4b24..188f6d1 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "v0.2.10-dev";
+  public static final String LABEL = "v0.2.11-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
index c7fc65d..09d6696 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -5,14 +5,13 @@
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.CompilationError;
-import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.objects.Reference2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
+import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -91,14 +90,59 @@
     return map;
   }
 
+  /**
+   * Here, 'depth' of a program class is an integer one bigger then the maximum depth of its
+   * superclass and implemented interfaces. The depth of classes without any or without known
+   * superclasses and interfaces is 1.
+   */
+  private static class ProgramClassDepthsMemoized {
+    private final DexApplication application;
+    private final Reference2IntMap<DexProgramClass> depthOfClasses = new Reference2IntArrayMap<>();
+
+    ProgramClassDepthsMemoized(DexApplication application) {
+      this.application = application;
+    }
+
+    int getDepth(DexProgramClass programClass) {
+      return depthOfClasses.computeIfAbsent(
+          programClass,
+          programClassToCompute -> {
+            // Emulating the algorithm of com.android.dx.merge.SortableType.tryAssignDepth().
+            DexType superType = programClassToCompute.superType;
+            int maxDepth;
+            if (superType == null) {
+              maxDepth = 0;
+            } else {
+              maxDepth = 1;
+              DexProgramClass superClass = application.programDefinitionFor(superType);
+              if (superClass != null) {
+                maxDepth = getDepth(superClass);
+              }
+            }
+            for (DexType inf : programClassToCompute.interfaces.values) {
+              DexProgramClass infClass = application.programDefinitionFor(inf);
+              maxDepth = Math.max(maxDepth, infClass == null ? 1 : getDepth(infClass));
+            }
+            return maxDepth + 1;
+          });
+    }
+  }
+
   private static DexProgramClass[] sortClasses(DexApplication application,
       Collection<DexProgramClass> classes) {
-    SortingProgramClassVisitor classVisitor = new SortingProgramClassVisitor(application, classes);
     // Collect classes in subtyping order, based on a sorted list of classes to start with.
-    classVisitor.run(
-        classes.stream().sorted(Comparator.comparing(DexClass::getType))
-            .collect(Collectors.toList()));
-    return classVisitor.getSortedClasses();
+    ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(application);
+    List<DexProgramClass> sortedClasses =
+        classes
+            .stream()
+            .sorted(
+                (x, y) -> {
+                  int dx = classDepths.getDepth(x);
+                  int dy = classDepths.getDepth(y);
+                  return dx != dy ? dx - dy : x.type.compareTo(y.type);
+                })
+            .collect(Collectors.toList());
+    return sortedClasses.toArray(new DexProgramClass[sortedClasses.size()]);
   }
 
   private static <T> Collection<T> keysOrEmpty(Map<T, ?> map) {
@@ -179,34 +223,4 @@
   public int getOffsetFor(DexMethodHandle methodHandle) {
     return getOffsetFor(methodHandle, methodHandles);
   }
-
-  private static class SortingProgramClassVisitor extends ProgramClassVisitor {
-    private final Set<DexClass> classSet = Sets.newIdentityHashSet();
-    private final DexProgramClass[] sortedClasses;
-
-    private int index = 0;
-
-    SortingProgramClassVisitor(DexApplication application,
-        Collection<DexProgramClass> classes) {
-      super(application);
-      this.sortedClasses = new DexProgramClass[classes.size()];
-      classSet.addAll(classes);
-    }
-
-    @Override
-    public void visit(DexType type) {}
-
-    @Override
-    public void visit(DexClass clazz) {
-      if (classSet.contains(clazz)) {
-        assert index < sortedClasses.length;
-        sortedClasses[index++] = (DexProgramClass) clazz;
-      }
-    }
-
-    DexProgramClass[] getSortedClasses() {
-      assert index == sortedClasses.length;
-      return sortedClasses;
-    }
-  }
 }
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 9789c44..870521d 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -536,6 +536,15 @@
       Log.verbose(getClass(), "Method `%s` is targeted.", encodedMethod.method);
     }
     targetedMethods.add(encodedMethod, reason);
+    if (options.forceProguardCompatibility) {
+      // Keep targeted default methods in compatibility mode. The tree pruner will otherwise make
+      // these methods abstract, whereas Proguard does not (seem to) touch their code.
+      DexClass clazz = appInfo.definitionFor(encodedMethod.method.holder);
+      if (!encodedMethod.accessFlags.isAbstract()
+          && clazz.isInterface() && !clazz.isLibraryClass()) {
+        markMethodAsKeptWithCompatRule(encodedMethod);
+      }
+    }
   }
 
   /**
@@ -1179,6 +1188,14 @@
     }
   }
 
+  private void markMethodAsKeptWithCompatRule(DexEncodedMethod method) {
+    ProguardKeepRule rule =
+        ProguardConfigurationUtils.buildDefaultMethodKeepRule(
+            appInfo.definitionFor(method.method.holder), method);
+    proguardCompatibilityWorkList.add(
+        Action.markMethodLive(method, KeepReason.dueToProguardCompatibilityKeepRule(rule)));
+  }
+
   private void handleProguardReflectiveBehavior(DexEncodedMethod method) {
     try {
       IRCode code = method.buildIR(options);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
index 9fea981..08610aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
@@ -5,7 +5,11 @@
 package com.android.tools.r8.shaking;
 
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
 import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
 
 public class ProguardConfigurationUtils {
   public static ProguardKeepRule buildDefaultInitializerKeepRule(DexClass clazz) {
@@ -27,4 +31,27 @@
     }
     return builder.build();
   }
+
+  public static ProguardKeepRule buildDefaultMethodKeepRule(
+      DexClass clazz, DexEncodedMethod method) {
+    assert clazz.type == method.method.holder;
+    ProguardKeepRule.Builder builder = ProguardKeepRule.builder();
+    builder.setType(ProguardKeepRuleType.KEEP);
+    builder.getModifiersBuilder().allowsObfuscation = true;
+    builder.getModifiersBuilder().allowsOptimization = true;
+    builder.getClassAccessFlags().setPublic();
+    builder.setClassType(ProguardClassType.INTERFACE);
+    builder.setClassNames(
+        ProguardClassNameList.singletonList(ProguardTypeMatcher.create(clazz.type)));
+    ProguardMemberRule.Builder memberRuleBuilder = ProguardMemberRule.builder();
+    memberRuleBuilder.setRuleType(ProguardMemberType.METHOD);
+    memberRuleBuilder.setName(method.method.name.toString());
+    memberRuleBuilder.setTypeMatcher(ProguardTypeMatcher.create(method.method.proto.returnType));
+    List<ProguardTypeMatcher> arguments = Arrays.stream(method.method.proto.parameters.values)
+        .map(ProguardTypeMatcher::create)
+        .collect(Collectors.toList());
+    memberRuleBuilder.setArguments(arguments);
+    builder.getMemberRules().add(memberRuleBuilder.build());
+    return builder.build();
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/defaultmethods/ClassImplementingInterface.java b/src/test/java/com/android/tools/r8/shaking/defaultmethods/ClassImplementingInterface.java
new file mode 100644
index 0000000..b8261ad
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/defaultmethods/ClassImplementingInterface.java
@@ -0,0 +1,11 @@
+// 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.shaking.defaultmethods;
+
+public class ClassImplementingInterface implements InterfaceWithDefaultMethods {
+  public int method() {
+    return 41;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
index 4fac23b..3de225d 100644
--- a/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.invokesuper.Consumer;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DexInspector;
 import com.android.tools.r8.utils.DexInspector.ClassSubject;
@@ -26,9 +27,10 @@
       throws Exception {
     R8Command.Builder builder = R8Command.builder();
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(InterfaceWithDefaultMethods.class));
+    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(ClassImplementingInterface.class));
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class));
     builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
-    builder.setMinApiLevel(26);
+    builder.setMinApiLevel(AndroidApiLevel.O.getLevel());
     // Always keep main in the test class, so the output never becomes empty.
     builder.addProguardConfiguration(ImmutableList.of(
         "-keep class " + TestClass.class.getCanonicalName() + "{",
@@ -59,6 +61,14 @@
     assertFalse(method.isAbstract());
   }
 
+  private void defaultMethodAbstract(DexInspector inspector) {
+    ClassSubject clazz = inspector.clazz(InterfaceWithDefaultMethods.class);
+    assertTrue(clazz.isPresent());
+    MethodSubject method = clazz.method("int", "method", ImmutableList.of());
+    assertTrue(method.isPresent());
+    assertTrue(method.isAbstract());
+  }
+
   @Test
   public void test() throws Exception {
     runTest(ImmutableList.of(), this::interfaceNotKept);
@@ -76,5 +86,18 @@
         "  public int method();",
         "}"
     ), this::defaultMethodKept);
+    runTest(ImmutableList.of(
+        "-keep class " + ClassImplementingInterface.class.getCanonicalName() + "{",
+        "  <methods>;",
+        "}"
+    ), this::defaultMethodNotKept);
+    runTest(ImmutableList.of(
+        "-keep class " + ClassImplementingInterface.class.getCanonicalName() + "{",
+        "  <methods>;",
+        "}",
+        "-keep class " + TestClass.class.getCanonicalName() + "{",
+        "  public void useInterfaceMethod();",
+        "}"
+    ), this::defaultMethodAbstract);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/defaultmethods/TestClass.java b/src/test/java/com/android/tools/r8/shaking/defaultmethods/TestClass.java
index fcb240a..5e46681 100644
--- a/src/test/java/com/android/tools/r8/shaking/defaultmethods/TestClass.java
+++ b/src/test/java/com/android/tools/r8/shaking/defaultmethods/TestClass.java
@@ -6,6 +6,11 @@
 
 public class TestClass {
 
+  public void useInterfaceMethod() {
+    InterfaceWithDefaultMethods iface = new ClassImplementingInterface();
+    System.out.println(iface.method());
+  }
+
   public static void main(String[] args) {
   }
 }
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
index 9679970..085e46c 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -16,15 +16,21 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.invokesuper.Consumer;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.ProguardClassNameList;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationParser;
+import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.shaking.ProguardMemberRule;
 import com.android.tools.r8.shaking.ProguardMemberType;
+import com.android.tools.r8.shaking.forceproguardcompatibility.defaultmethods.ClassImplementingInterface;
+import com.android.tools.r8.shaking.forceproguardcompatibility.defaultmethods.InterfaceWithDefaultMethods;
+import com.android.tools.r8.shaking.forceproguardcompatibility.defaultmethods.TestClass;
 import com.android.tools.r8.shaking.forceproguardcompatibility.keepattributes.TestKeepAttributes;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
 import com.android.tools.r8.utils.DexInspector;
@@ -373,4 +379,115 @@
     testKeepAttributes(false, false, true);
     testKeepAttributes(false, true, true);
   }
+
+  private void runKeepDefaultMethodsTest(
+      List<String> additionalKeepRules,
+      Consumer<DexInspector> inspection,
+      Consumer<ProguardConfiguration> compatInspection) throws Exception {
+    Class mainClass = TestClass.class;
+    CompatProguardCommandBuilder builder = new CompatProguardCommandBuilder();
+    builder.addProgramFiles(ToolHelper.getClassFilesForTestPackage(mainClass.getPackage()));
+    builder.addProguardConfiguration(ImmutableList.of(
+        "-keep class " + mainClass.getCanonicalName() + "{",
+        "  public <init>();",
+        "  public static void main(java.lang.String[]);",
+        "}",
+        "-dontobfuscate"),
+        Origin.unknown());
+    builder.addProguardConfiguration(additionalKeepRules, Origin.unknown());
+    builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
+    builder.setMinApiLevel(AndroidApiLevel.O.getLevel());
+    Path proguardCompatibilityRules = temp.newFile().toPath();
+    builder.setProguardCompatibilityRulesOutput(proguardCompatibilityRules);
+    AndroidApp app = ToolHelper.runR8(builder.build());
+    inspection.accept(new DexInspector(app));
+    // Check the Proguard compatibility configuration generated.
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(),
+            new Reporter(new DefaultDiagnosticsHandler()));
+    parser.parse(proguardCompatibilityRules);
+    ProguardConfiguration configuration = parser.getConfigRawForTesting();
+    compatInspection.accept(configuration);
+  }
+
+  private void noCompatibilityRules(ProguardConfiguration configuration) {
+    assertEquals(0, configuration.getRules().size());
+  }
+
+  private void defaultMethodKept(DexInspector inspector) {
+    ClassSubject clazz = inspector.clazz(InterfaceWithDefaultMethods.class);
+    assertTrue(clazz.isPresent());
+    MethodSubject method = clazz.method("int", "method", ImmutableList.of());
+    assertTrue(method.isPresent());
+    assertFalse(method.isAbstract());
+  }
+
+  private void defaultMethodCompatibilityRules(ProguardConfiguration configuration) {
+    assertEquals(1, configuration.getRules().size());
+    ProguardConfigurationRule rule = configuration.getRules().get(0);
+    Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+    ProguardClassNameList classNames = rule.getClassNames();
+    assertEquals(1, classNames.size());
+    DexType type = classNames.asSpecificDexTypes().get(0);
+    assertEquals(type.toSourceString(), InterfaceWithDefaultMethods.class.getCanonicalName());
+    assertEquals(1, memberRules.size());
+    ProguardMemberRule memberRule = memberRules.iterator().next();
+    assertEquals(ProguardMemberType.METHOD, memberRule.getRuleType());
+    assertTrue(memberRule.getName().matches("method"));
+    assertTrue(memberRule.getType().matches(configuration.getDexItemFactory().intType));
+    assertEquals(0, memberRule.getArguments().size());
+  }
+
+  private void defaultMethod2Kept(DexInspector inspector) {
+    ClassSubject clazz = inspector.clazz(InterfaceWithDefaultMethods.class);
+    assertTrue(clazz.isPresent());
+    MethodSubject method =
+        clazz.method("void", "method2", ImmutableList.of("java.lang.String", "int"));
+    assertTrue(method.isPresent());
+    assertFalse(method.isAbstract());
+  }
+
+  private void defaultMethod2CompatibilityRules(ProguardConfiguration configuration) {
+    assertEquals(1, configuration.getRules().size());
+    ProguardConfigurationRule rule = configuration.getRules().get(0);
+    Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+    ProguardClassNameList classNames = rule.getClassNames();
+    assertEquals(1, classNames.size());
+    DexType type = classNames.asSpecificDexTypes().get(0);
+    assertEquals(type.toSourceString(), InterfaceWithDefaultMethods.class.getCanonicalName());
+    assertEquals(1, memberRules.size());
+    ProguardMemberRule memberRule = memberRules.iterator().next();
+    assertEquals(ProguardMemberType.METHOD, memberRule.getRuleType());
+    assertTrue(memberRule.getName().matches("method2"));
+    assertTrue(memberRule.getType().matches(configuration.getDexItemFactory().voidType));
+    assertEquals(2, memberRule.getArguments().size());
+    assertTrue(
+        memberRule.getArguments().get(0).matches(configuration.getDexItemFactory().stringType));
+    assertTrue(memberRule.getArguments().get(1).matches(configuration.getDexItemFactory().intType));
+  }
+
+  @Test
+  public void keepDefaultMethodsTest() throws Exception {
+    runKeepDefaultMethodsTest(ImmutableList.of(
+        "-keep interface " + InterfaceWithDefaultMethods.class.getCanonicalName() + "{",
+        "  public int method();",
+        "}"
+    ), this::defaultMethodKept, this::noCompatibilityRules);
+    runKeepDefaultMethodsTest(ImmutableList.of(
+        "-keep class " + ClassImplementingInterface.class.getCanonicalName() + "{",
+        "  <methods>;",
+        "}",
+        "-keep class " + TestClass.class.getCanonicalName() + "{",
+        "  public void useInterfaceMethod();",
+        "}"
+    ), this::defaultMethodKept, this::defaultMethodCompatibilityRules);
+    runKeepDefaultMethodsTest(ImmutableList.of(
+        "-keep class " + ClassImplementingInterface.class.getCanonicalName() + "{",
+        "  <methods>;",
+        "}",
+        "-keep class " + TestClass.class.getCanonicalName() + "{",
+        "  public void useInterfaceMethod2();",
+        "}"
+    ), this::defaultMethod2Kept, this::defaultMethod2CompatibilityRules);
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/ClassImplementingInterface.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/ClassImplementingInterface.java
new file mode 100644
index 0000000..9b5adfe
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/ClassImplementingInterface.java
@@ -0,0 +1,13 @@
+// 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.shaking.forceproguardcompatibility.defaultmethods;
+
+public class ClassImplementingInterface implements InterfaceWithDefaultMethods {
+  public int method() {
+    return 41;
+  }
+  public void method2(String x, int y) {
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/InterfaceWithDefaultMethods.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/InterfaceWithDefaultMethods.java
new file mode 100644
index 0000000..d7503d6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/InterfaceWithDefaultMethods.java
@@ -0,0 +1,14 @@
+// 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.shaking.forceproguardcompatibility.defaultmethods;
+
+public interface InterfaceWithDefaultMethods {
+  default int method() {
+    return 42;
+  }
+  default void method2(String x, int y) {
+    System.out.println(y + x);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/TestClass.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/TestClass.java
new file mode 100644
index 0000000..35ba3c5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultmethods/TestClass.java
@@ -0,0 +1,21 @@
+// 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.shaking.forceproguardcompatibility.defaultmethods;
+
+public class TestClass {
+
+  public void useInterfaceMethod() {
+    InterfaceWithDefaultMethods iface = new ClassImplementingInterface();
+    System.out.println(iface.method());
+  }
+
+  public void useInterfaceMethod2() {
+    InterfaceWithDefaultMethods iface = new ClassImplementingInterface();
+    iface.method2("a", 1);
+  }
+
+  public static void main(String[] args) {
+  }
+}