Use repackaging framework for minifying packages

ClassNameMinifier do not know about package privacy. This CL adds a
minification option for repackaging to check for -keeppackagenames and
allows for the ClassNameMinifier to rely on all classes being placed
in packages already.

Bug: 172496438
Bug: 150589374
Bug: 172254047
Change-Id: I1fb747691ff5da030bc5d2792a80e1db3dd3d752
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 afc04c7..5c9fc0f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1184,6 +1184,9 @@
       return this;
     }
     Builder builder = builder(this);
+    if (isNonPrivateVirtualMethod() && isLibraryMethodOverride() != OptionalBool.unknown()) {
+      builder.setIsLibraryMethodOverride(isLibraryMethodOverride());
+    }
     builder.setMethod(method);
     // TODO(b/112847660): Fix type fixers that use this method: Class staticizer
     // TODO(b/112847660): Fix type fixers that use this method: Uninstantiated type optimization
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 0752d20..d1c5b3f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -2330,8 +2330,17 @@
       MethodHandleType type,
       DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod,
       boolean isInterface) {
+    return createMethodHandle(type, fieldOrMethod, isInterface, null);
+  }
+
+  public DexMethodHandle createMethodHandle(
+      MethodHandleType type,
+      DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod,
+      boolean isInterface,
+      DexMethod rewrittenTarget) {
     assert !sorted;
-    DexMethodHandle methodHandle = new DexMethodHandle(type, fieldOrMethod, isInterface);
+    DexMethodHandle methodHandle =
+        new DexMethodHandle(type, fieldOrMethod, isInterface, rewrittenTarget);
     return canonicalize(methodHandles, methodHandle);
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
index 0bdb208..71bc104 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -207,13 +207,6 @@
   public DexMethodHandle(
       MethodHandleType type,
       DexMember<? extends DexItem, ? extends DexMember<?, ?>> member,
-      boolean isInterface) {
-    this(type, member, isInterface, null);
-  }
-
-  public DexMethodHandle(
-      MethodHandleType type,
-      DexMember<? extends DexItem, ? extends DexMember<?, ?>> member,
       boolean isInterface,
       DexMethod rewrittenTarget) {
     this.type = type;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
index 4bc8714..b8a70f9 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
@@ -137,17 +137,21 @@
       if (newType != oldType || actualTarget != invokedMethod || rewrittenTarget != actualTarget) {
         DexClass holder = definitions.definitionFor(actualTarget.holder, context);
         boolean isInterface = holder != null ? holder.isInterface() : methodHandle.isInterface;
-        return new DexMethodHandle(
-            newType,
-            actualTarget,
-            isInterface,
-            rewrittenTarget != actualTarget ? rewrittenTarget : null);
+        return definitions
+            .dexItemFactory()
+            .createMethodHandle(
+                newType,
+                actualTarget,
+                isInterface,
+                rewrittenTarget != actualTarget ? rewrittenTarget : null);
       }
     } else {
       DexField field = methodHandle.asField();
       DexField actualField = graphLens().lookupField(field);
       if (actualField != field) {
-        return new DexMethodHandle(methodHandle.type, actualField, methodHandle.isInterface);
+        return definitions
+            .dexItemFactory()
+            .createMethodHandle(methodHandle.type, actualField, methodHandle.isInterface);
       }
     }
     return methodHandle;
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 3a25d00..1587e8a 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jar;
 
+import static com.android.tools.r8.repackaging.Repackaging.DefaultRepackagingConfiguration.TEMPORARY_PACKAGE_NAME;
 import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
 
 import com.android.tools.r8.ByteDataView;
@@ -185,6 +186,7 @@
     }
     String desc = namingLens.lookupDescriptor(clazz.type).toString();
     String name = namingLens.lookupInternalName(clazz.type);
+    assert !name.contains(TEMPORARY_PACKAGE_NAME);
     String signature = clazz.getClassSignature().toRenamedString(namingLens, isTypeMissing);
     String superName =
         clazz.type == options.itemFactory.objectType
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index 8aa95b2..2e1ddf9 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
@@ -36,6 +35,10 @@
     assert unknown != null;
   }
 
+  public DexType getKnown() {
+    return known;
+  }
+
   static KotlinTypeReference fromBinaryName(String binaryName, DexItemFactory factory) {
     if (DescriptorUtils.isValidBinaryName(binaryName)) {
       return fromDescriptor(
@@ -63,19 +66,11 @@
       return unknown;
     }
     assert known != null;
-    if (!known.isClassType()) {
-      return known.descriptor.toString();
-    }
-    DexType rewrittenType = appView.graphLens().lookupClassType(known);
-    if (appView.appInfo().hasLiveness()
-        && !appView.withLiveness().appInfo().isNonProgramTypeOrLiveProgramType(rewrittenType)) {
+    DexType rewrittenType = toRewrittenTypeOrNull(appView, known);
+    if (rewrittenType == null) {
       return defaultValue;
     }
-    DexString descriptor = namingLens.lookupDescriptor(rewrittenType);
-    if (descriptor != null) {
-      return descriptor.toString();
-    }
-    return defaultValue;
+    return namingLens.lookupDescriptor(rewrittenType).toString();
   }
 
   String toRenamedBinaryNameOrDefault(
@@ -95,6 +90,25 @@
     return DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
   }
 
+  private static DexType toRewrittenTypeOrNull(AppView<?> appView, DexType type) {
+    if (type.isArrayType()) {
+      DexType rewrittenBaseType =
+          toRewrittenTypeOrNull(appView, type.toBaseType(appView.dexItemFactory()));
+      return rewrittenBaseType != null
+          ? type.replaceBaseType(rewrittenBaseType, appView.dexItemFactory())
+          : null;
+    }
+    if (!type.isClassType()) {
+      return type;
+    }
+    DexType rewrittenType = appView.graphLens().lookupClassType(type);
+    if (appView.appInfo().hasLiveness()
+        && !appView.withLiveness().appInfo().isNonProgramTypeOrLiveProgramType(rewrittenType)) {
+      return null;
+    }
+    return rewrittenType;
+  }
+
   @Override
   public String toString() {
     return known != null ? known.descriptor.toString() : unknown;
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 771c336..e6937ea 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -39,8 +39,6 @@
   private final ClassNamingStrategy classNamingStrategy;
   private final PackageNamingStrategy packageNamingStrategy;
   private final Iterable<? extends DexClass> classes;
-  private final boolean isAccessModificationAllowed;
-  private final Set<String> noObfuscationPrefixes = Sets.newHashSet();
   private final Set<String> usedPackagePrefixes = Sets.newHashSet();
   private final Set<String> usedTypeNames = Sets.newHashSet();
   private final Map<DexType, DexString> renaming = Maps.newIdentityHashMap();
@@ -50,6 +48,7 @@
   private final Namespace topLevelState;
   private final boolean allowMixedCaseNaming;
   private final Predicate<String> isUsed;
+  private final ProguardPackageNameList keepPackageNames;
 
   ClassNameMinifier(
       AppView<AppInfoWithLiveness> appView,
@@ -61,8 +60,6 @@
     this.packageNamingStrategy = packageNamingStrategy;
     this.classes = classes;
     InternalOptions options = appView.options();
-    this.isAccessModificationAllowed =
-        options.getProguardConfiguration().isAccessModificationAllowed();
     this.keepInnerClassStructure = options.keepInnerClassStructure();
 
     // Initialize top-level naming state.
@@ -70,9 +67,8 @@
     String newPackageDescriptor =
         StringUtils.replaceAll(options.getProguardConfiguration().getPackagePrefix(), ".", "/");
     if (!newPackageDescriptor.isEmpty()) {
-      registerPackagePrefixesAsUsed(newPackageDescriptor, false);
+      registerPackagePrefixesAsUsed(newPackageDescriptor);
     }
-
     states.put("", topLevelState);
 
     if (options.getProguardConfiguration().hasDontUseMixedCaseClassnames()) {
@@ -82,6 +78,7 @@
       allowMixedCaseNaming = true;
       isUsed = usedTypeNames::contains;
     }
+    keepPackageNames = options.getProguardConfiguration().getKeepPackageNamesPatterns();
   }
 
   private void setUsedTypeName(String typeName) {
@@ -180,8 +177,7 @@
   private void registerClassAsUsed(DexType type, DexString descriptor) {
     renaming.put(type, descriptor);
     registerPackagePrefixesAsUsed(
-        getParentPackagePrefix(getClassBinaryNameFromDescriptor(descriptor.toSourceString())),
-        isAccessModificationAllowed);
+        getParentPackagePrefix(getClassBinaryNameFromDescriptor(descriptor.toSourceString())));
     setUsedTypeName(descriptor.toString());
     if (keepInnerClassStructure) {
       DexType outerClass = getOutClassForType(type);
@@ -197,15 +193,13 @@
   }
 
   /** Registers the given package prefix and all of parent packages as used. */
-  private void registerPackagePrefixesAsUsed(String packagePrefix, boolean isMinificationAllowed) {
-    // If -allowaccessmodification is not set, we may keep classes in their original packages,
-    // accounting for package-private accesses.
-    if (!isMinificationAllowed) {
-      noObfuscationPrefixes.add(packagePrefix);
-    }
+  private void registerPackagePrefixesAsUsed(String packagePrefix) {
     String usedPrefix = packagePrefix;
     while (usedPrefix.length() > 0) {
+      // Only reserve the actual package and not all parent packages.
+      // TODO(b/178563208): Only mark prefix as used if usedPrefix.equals(packagePrefix)
       usedPackagePrefixes.add(usedPrefix);
+      states.computeIfAbsent(usedPrefix, Namespace::new);
       usedPrefix = getParentPackagePrefix(usedPrefix);
     }
   }
@@ -259,9 +253,7 @@
     String packageName = getPackageBinaryNameFromJavaType(type.getPackageDescriptor());
     // Check whether the given class should be kept.
     // or check whether the given class belongs to a package that is kept for another class.
-    ProguardPackageNameList keepPackageNames =
-        appView.options().getProguardConfiguration().getKeepPackageNamesPatterns();
-    if (noObfuscationPrefixes.contains(packageName) || keepPackageNames.matches(type)) {
+    if (keepPackageNames.matches(type)) {
       return states.computeIfAbsent(packageName, Namespace::new);
     }
     return getStateForPackagePrefix(packageName);
@@ -272,15 +264,9 @@
     if (state == null) {
       // Calculate the parent package prefix, e.g., La/b/c -> La/b
       String parentPackage = getParentPackagePrefix(prefix);
-      Namespace superState;
-      if (noObfuscationPrefixes.contains(parentPackage)) {
-        // Restore a state for parent package prefix if it should be kept.
-        superState = states.computeIfAbsent(parentPackage, Namespace::new);
-      } else {
-        // Create a state for parent package prefix, if necessary, in a recursive manner.
-        // That recursion should end when the parent package hits the top-level, "".
-        superState = getStateForPackagePrefix(parentPackage);
-      }
+      // Create a state for parent package prefix, if necessary, in a recursive manner.
+      // That recursion should end when the parent package hits the top-level, "".
+      Namespace superState = getStateForPackagePrefix(parentPackage);
       // From the super state, get a renamed package prefix for the current level.
       String renamedPackagePrefix = superState.nextPackagePrefix();
       // Create a new state, which corresponds to a new name space, for the current level.
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index eba0a87..cdfa649 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -9,6 +9,7 @@
 import static com.android.tools.r8.utils.DescriptorUtils.INNER_CLASS_SEPARATOR;
 
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
@@ -26,6 +27,7 @@
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.synthesis.CommittedItems;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
@@ -291,26 +293,46 @@
 
   public static class DefaultRepackagingConfiguration implements RepackagingConfiguration {
 
+    private final AppView<?> appView;
     private final DexItemFactory dexItemFactory;
     private final ProguardConfiguration proguardConfiguration;
+    public static final String TEMPORARY_PACKAGE_NAME = "TEMPORARY_PACKAGE_NAME_FOR_";
 
-    public DefaultRepackagingConfiguration(
-        DexItemFactory dexItemFactory, ProguardConfiguration proguardConfiguration) {
-      this.dexItemFactory = dexItemFactory;
-      this.proguardConfiguration = proguardConfiguration;
+    public DefaultRepackagingConfiguration(AppView<?> appView) {
+      this.appView = appView;
+      this.dexItemFactory = appView.dexItemFactory();
+      this.proguardConfiguration = appView.options().getProguardConfiguration();
     }
 
     @Override
     public String getNewPackageDescriptor(ProgramPackage pkg, Set<String> seenPackageDescriptors) {
       String newPackageDescriptor =
           DescriptorUtils.getBinaryNameFromJavaType(proguardConfiguration.getPackagePrefix());
-      if (proguardConfiguration.getPackageObfuscationMode().isRepackageClasses()) {
+      PackageObfuscationMode packageObfuscationMode =
+          proguardConfiguration.getPackageObfuscationMode();
+      if (packageObfuscationMode.isRepackageClasses()) {
         return newPackageDescriptor;
       }
+      assert packageObfuscationMode.isFlattenPackageHierarchy()
+          || packageObfuscationMode.isMinification();
       if (!newPackageDescriptor.isEmpty()) {
         newPackageDescriptor += DESCRIPTOR_PACKAGE_SEPARATOR;
       }
-      newPackageDescriptor += pkg.getLastPackageName();
+      if (packageObfuscationMode.isMinification()) {
+        assert !proguardConfiguration.hasApplyMappingFile();
+        // Always keep top-level classes since there packages can never be minified.
+        if (pkg.getPackageDescriptor().equals("")
+            || proguardConfiguration.getKeepPackageNamesPatterns().matches(pkg)
+            || mayHavePinnedPackagePrivateOrProtectedItem(pkg)) {
+          return pkg.getPackageDescriptor();
+        }
+        // For us to rename shaking/A to a/a if we have a class shaking/Kept, we have to propose
+        // a different name than the last package name - the class will be minified in
+        // ClassNameMinifier.
+        newPackageDescriptor += TEMPORARY_PACKAGE_NAME + pkg.getLastPackageName();
+      } else {
+        newPackageDescriptor += pkg.getLastPackageName();
+      }
       String finalPackageDescriptor = newPackageDescriptor;
       for (int i = 1; seenPackageDescriptors.contains(finalPackageDescriptor); i++) {
         finalPackageDescriptor = newPackageDescriptor + INNER_CLASS_SEPARATOR + i;
@@ -318,6 +340,24 @@
       return finalPackageDescriptor;
     }
 
+    private boolean mayHavePinnedPackagePrivateOrProtectedItem(ProgramPackage pkg) {
+      // Go through all package classes and members to see if there is a pinned package-private
+      // item, in which case we cannot move it because there may be a reflective access to it.
+      for (DexProgramClass clazz : pkg.classesInPackage()) {
+        if (clazz.getAccessFlags().isPackagePrivateOrProtected()
+            && appView.getKeepInfo().getClassInfo(clazz).isPinned()) {
+          return true;
+        }
+        for (DexEncodedMember<?, ?> member : clazz.members()) {
+          if (member.getAccessFlags().isPackagePrivateOrProtected()
+              && appView.getKeepInfo().getMemberInfo(member, clazz).isPinned()) {
+            return true;
+          }
+        }
+      }
+      return false;
+    }
+
     @Override
     public DexType getRepackagedType(
         DexProgramClass clazz,
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
index da98174..81239aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
@@ -72,6 +73,14 @@
    */
   public abstract KeepFieldInfo getFieldInfo(DexEncodedField field, DexProgramClass holder);
 
+  public KeepMemberInfo<?, ?> getMemberInfo(DexEncodedMember<?, ?> member, DexProgramClass holder) {
+    if (member.isDexEncodedField()) {
+      return getFieldInfo(member.asDexEncodedField(), holder);
+    }
+    assert member.isDexEncodedMethod();
+    return getMethodInfo(member.asDexEncodedMethod(), holder);
+  }
+
   public final KeepClassInfo getClassInfo(DexType type, DexDefinitionSupplier definitions) {
     DexProgramClass clazz = asProgramClassOrNull(definitions.definitionFor(type));
     return clazz == null ? keepInfoForNonProgramClass() : getClassInfo(clazz);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 8fdd330..6d3a8ca 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -397,6 +397,12 @@
         synthesizeKeepRulesForRecompilation();
       }
 
+      if (packageObfuscationMode == PackageObfuscationMode.NONE
+          && obfuscating
+          && !hasApplyMappingFile()) {
+        packageObfuscationMode = PackageObfuscationMode.MINIFICATION;
+      }
+
       return buildRaw();
     }
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardPackageMatcher.java b/src/main/java/com/android/tools/r8/shaking/ProguardPackageMatcher.java
index 48c4703..f31087d 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardPackageMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardPackageMatcher.java
@@ -4,8 +4,6 @@
 
 package com.android.tools.r8.shaking;
 
-import com.android.tools.r8.graph.DexType;
-
 public class ProguardPackageMatcher {
   private final String pattern;
 
@@ -13,8 +11,8 @@
     this.pattern = pattern;
   }
 
-  public boolean matches(DexType type) {
-    return matchPackageNameImpl(pattern, 0, type.getPackageName(), 0);
+  public boolean matches(String packageName) {
+    return matchPackageNameImpl(pattern, 0, packageName, 0);
   }
 
   private static boolean matchPackageNameImpl(
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardPackageNameList.java b/src/main/java/com/android/tools/r8/shaking/ProguardPackageNameList.java
index 6d45459..6dcd07b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardPackageNameList.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardPackageNameList.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.shaking;
 
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramPackage;
 import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
 import it.unimi.dsi.fastutil.objects.ObjectIterator;
@@ -56,9 +57,17 @@
   }
 
   public boolean matches(DexType type) {
+    return matches(type.getPackageName());
+  }
+
+  public boolean matches(ProgramPackage pkg) {
+    return matches(pkg.getPackageName());
+  }
+
+  private boolean matches(String pkgName) {
     for (Object2BooleanMap.Entry<ProguardPackageMatcher> packageName :
         packageNames.object2BooleanEntrySet()) {
-      if (packageName.getKey().matches(type)) {
+      if (packageName.getKey().matches(pkgName)) {
         // If we match a negation, abort as non-match. If we match a positive, return true.
         return !packageName.getBooleanValue();
       }
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 4e787b6..ea310aa 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1046,8 +1046,11 @@
   }
 
   public enum PackageObfuscationMode {
-    // General package obfuscation.
+    // No package obfuscation.
     NONE,
+    // Strategy based on ordinary package obfuscation when no package-obfuscation mode is specified
+    // by the users. In practice this falls back to FLATTEN but with keeping package-names.
+    MINIFICATION,
     // Repackaging all classes into the single user-given (or top-level) package.
     REPACKAGE,
     // Repackaging all packages into the single user-given (or top-level) package.
@@ -1065,6 +1068,10 @@
       return this == REPACKAGE;
     }
 
+    public boolean isMinification() {
+      return this == MINIFICATION;
+    }
+
     public boolean isSome() {
       return !isNone();
     }
@@ -1242,10 +1249,7 @@
     public Consumer<String> processingContextsConsumer = null;
 
     public Function<AppView<AppInfoWithLiveness>, RepackagingConfiguration>
-        repackagingConfigurationFactory =
-            appView ->
-                new DefaultRepackagingConfiguration(
-                    appView.dexItemFactory(), appView.options().getProguardConfiguration());
+        repackagingConfigurationFactory = DefaultRepackagingConfiguration::new;
 
     public BiConsumer<DexItemFactory, HorizontallyMergedClasses> horizontallyMergedClassesConsumer =
         ConsumerUtils.emptyBiConsumer();
diff --git a/src/test/examples/naming101/c.java b/src/test/examples/naming101/c.java
index 21744bc..7477024 100644
--- a/src/test/examples/naming101/c.java
+++ b/src/test/examples/naming101/c.java
@@ -4,5 +4,5 @@
 package naming101;
 
 public class c {
-  public static int i = 1;
+  static int i = 1;
 }
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 1ad5db8..aad62cb 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8;
 
-
 import com.android.tools.r8.TestBase.Backend;
 import com.android.tools.r8.dexsplitter.SplitterTestBase.RunInterface;
 import com.android.tools.r8.references.MethodReference;
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java
index 630ff62..5a9da04 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java
@@ -23,6 +23,7 @@
 
   private final TestParameters parameters;
   private final String[] EXPECTED = new String[] {"SubViewModel.clear()", "ViewModel.clear()"};
+  private final String[] R8_OUT = new String[] {"SubViewModel.clear()", "SubViewModel.clear()"};
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -50,12 +51,9 @@
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .allowAccessModification()
-        .addOptionsModification(
-            options -> {
-              options.enablePackagePrivateAwarePublicization = true;
-            })
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::assertSuccessOutput);
+        // TODO(b/172496438): This should be EXPECTED.
+        .assertSuccessWithOutputLines(R8_OUT);
   }
 
   private void assertSuccessOutput(TestRunResult<?> result) {
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/InvalidBootstrapMethodHandleTestClass.java b/src/test/java/com/android/tools/r8/cf/methodhandles/InvalidBootstrapMethodHandleTestClass.java
index 9040a68..d63ead6 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/InvalidBootstrapMethodHandleTestClass.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/InvalidBootstrapMethodHandleTestClass.java
@@ -25,6 +25,7 @@
   public int nonStaticField = 42;
 
   // Virtual method to target.
+  @Override
   public CallSite virtualMethod(MethodHandles.Lookup caller, String name, MethodType type)
       throws Exception {
     return new ConstantCallSite(caller.findStatic(caller.lookupClass(), name, type));
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java
index 04bb9d7..c551a26 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java
@@ -32,18 +32,19 @@
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
+        .addKeepPackageNamesRule(Main.class.getPackage())
         .addHorizontallyMergedClassesInspector(
             HorizontallyMergedClassesInspector::assertNoClassesMerged)
         .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatMatches(
-            allOf(
-                containsString("java.lang.UnsatisfiedLinkError:"),
-                containsString("com.android.tools.r8.classmerging.horizontal.b.a(")))
         .inspectFailure(
             codeInspector -> {
               assertThat(codeInspector.clazz(A.class), isPresent());
               assertThat(codeInspector.clazz(B.class), isPresent());
-            });
+            })
+        .assertFailureWithErrorThatMatches(
+            allOf(
+                containsString("java.lang.UnsatisfiedLinkError:"),
+                containsString("com.android.tools.r8.classmerging.horizontal.b.a(")));
   }
 
   @NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
index 034f226..68e882e 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
@@ -388,7 +388,7 @@
         buildWithMemberNamesRule(testForR8(parameters.getBackend())).compile());
   }
 
-  // Tests for "-keepclassmembernames" and *no* minification.
+  // Tests for "-keepclassmembernames" and minification.
 
   private <
           C extends BaseCompilerCommand,
diff --git a/src/test/java/com/android/tools/r8/compatproguard/KeepClassMemberNamesMinificationTest.java b/src/test/java/com/android/tools/r8/compatproguard/KeepClassMemberNamesMinificationTest.java
new file mode 100644
index 0000000..009cf9f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compatproguard/KeepClassMemberNamesMinificationTest.java
@@ -0,0 +1,120 @@
+// 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.compatproguard;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.ProguardVersion;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KeepClassMemberNamesMinificationTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public KeepClassMemberNamesMinificationTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testForRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(Main.class, A.class, ReflectiveCallerOfA.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Hello World!", "Hello World!");
+  }
+
+  @Test
+  public void testPG() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testKeepNames(testForProguard(ProguardVersion.V7_0_0).addKeepRules("-dontwarn"));
+  }
+
+  @Test
+  public void testR8Compat() throws Exception {
+    testKeepNames(
+        testForR8Compat(parameters.getBackend())
+            .enableInliningAnnotations()
+            .enableNeverClassInliningAnnotations());
+  }
+
+  @Test
+  public void testR8Full() throws Exception {
+    testKeepNames(
+        testForR8(parameters.getBackend())
+            .enableInliningAnnotations()
+            .enableNeverClassInliningAnnotations());
+  }
+
+  private void testKeepNames(TestShrinkerBuilder<?, ?, ?, ?, ?> shrinkerBuilder) throws Exception {
+    shrinkerBuilder
+        .addProgramClasses(Main.class, A.class, ReflectiveCallerOfA.class)
+        .addKeepMainRule(Main.class)
+        .addKeepClassAndMembersRulesWithAllowObfuscation(A.class)
+        .addKeepRules("-keepclassmembernames class ** { *; }")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject aClass = inspector.clazz(A.class);
+              assertThat(aClass, isPresentAndRenamed());
+              assertThat(aClass.uniqueFieldWithName("foo"), isPresentAndNotRenamed());
+              assertThat(aClass.uniqueMethodWithName("foo"), isPresentAndNotRenamed());
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Hello World!", "Hello World!");
+  }
+
+  @NeverClassInline
+  public static class A {
+
+    public String foo = "Hello World!";
+
+    public void foo() {
+      System.out.println("Hello World!");
+    }
+
+    @NeverInline
+    public void callMySelf() throws Exception {
+      ReflectiveCallerOfA.callA(this.getClass().getName());
+    }
+  }
+
+  public static class ReflectiveCallerOfA {
+
+    @NeverInline
+    public static void callA(String className) throws Exception {
+      Class<?> aClass = Class.forName(className);
+      Object o = aClass.getDeclaredConstructor().newInstance();
+      System.out.println(aClass.getDeclaredField("foo").get(o));
+      aClass.getDeclaredMethod("foo").invoke(o);
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) throws Exception {
+      new A().callMySelf();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index ccd3cdf..0ee446d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -99,10 +99,8 @@
             shrinkDesugaredLibrary)
         .addRunClasspathFiles(CUSTOM_LIB)
         .run(parameters.getRuntime(), Executor.class)
-        .apply(
-            r ->
-                r.assertSuccessWithOutput(
-                    supportAllCallbacksFromLibrary ? EXPECTED_RESULT : FAILING_EXPECTED_RESULT));
+        .assertSuccessWithOutput(
+            supportAllCallbacksFromLibrary ? EXPECTED_RESULT : FAILING_EXPECTED_RESULT);
   }
 
   private void assertDoubleForEach(CodeInspector inspector) {
@@ -164,10 +162,8 @@
             shrinkDesugaredLibrary)
         .addRunClasspathFiles(CUSTOM_LIB)
         .run(parameters.getRuntime(), Executor.class)
-        .apply(
-            r ->
-                r.assertSuccessWithOutput(
-                    supportAllCallbacksFromLibrary ? EXPECTED_RESULT : FAILING_EXPECTED_RESULT));
+        .assertSuccessWithOutput(
+            supportAllCallbacksFromLibrary ? EXPECTED_RESULT : FAILING_EXPECTED_RESULT);
   }
 
   static class CustomLibClass {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
index b62045b..a96a874 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
@@ -8,7 +8,6 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.desugar.desugaredlibrary.conversiontests.MoreFunctionConversionTest.CustomLibClass;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
index f1884e9..2abe133 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
@@ -96,6 +96,7 @@
             })
         .addProgramFiles(classesMatching(outerNestName))
         .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
+        .addKeepPackageNamesRule("nesthostexample")
         .addInliningAnnotations()
         .compile()
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
index 073c7b1..9f41a17 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
@@ -99,6 +99,7 @@
             .enableInliningAnnotations()
             .addProgramFiles(bothNestsAndOutsideClassToCompile)
             .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
+            .addKeepPackageNamesRule("nesthostexample")
             .compile()
             .inspect(NestAttributesUpdateTest::assertNestAttributesCorrect);
     for (int i = 0; i < mainClasses.length; i++) {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
index 227ce07..7cc81c3 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
@@ -86,6 +86,7 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .minification(minification)
+        .addKeepPackageNamesRule(libClass.getPackage())
         .setMinApi(parameters.getApiLevel())
         .compile()
         .writeToZip();
diff --git a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
index 4be7975..a94f02a 100644
--- a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
@@ -49,8 +49,9 @@
     if (parameters.getRuntime().asCf().isNewerThan(CfVm.JDK8)) {
       runResult.assertFailureWithErrorThatMatches(
           containsString(
-              "java.lang.IncompatibleClassChangeError: Method"
-                  + " com.android.tools.r8.graph.invokestatic.InvokeStaticOnInterfaceTest$I.foo()V"
+              "java.lang.IncompatibleClassChangeError: Method "
+                  + I.class.getTypeName()
+                  + ".foo()V"
                   + " must be InterfaceMethodref constant"));
     } else {
       runResult.assertSuccessWithOutputLines("Hello World!");
@@ -79,13 +80,14 @@
             .enableInliningAnnotations()
             .enableNoVerticalClassMergingAnnotations()
             .addOptionsModification(o -> o.testing.allowInvokeErrors = true)
+            .noMinification()
             .addKeepMainRule(Main.class)
             .run(parameters.getRuntime(), Main.class);
     if (parameters.getRuntime().asCf().isNewerThan(CfVm.JDK8)) {
       runResult.assertFailureWithErrorThatMatches(
           containsString(
               "java.lang.IncompatibleClassChangeError: Method"
-                  + " com.android.tools.r8.graph.invokestatic.a.a()V"
+                  + " com.android.tools.r8.graph.invokestatic.InvokeStaticOnInterfaceTest$I.foo()V"
                   + " must be InterfaceMethodref constant"));
     } else {
       runResult.assertSuccessWithOutputLines("Hello World!");
diff --git a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
index 2811374..6a01e83 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
@@ -86,6 +86,7 @@
     return String.join(
         System.lineSeparator(),
         adaptResourceFilenamesRule,
+        "-keeppackagenames adaptresourcefilenames**",
         "-keep class adaptresourcefilenames.TestClass {",
         "  public static void main(...);",
         "}");
diff --git a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
index 8feb257..4a35018 100644
--- a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
@@ -47,16 +47,16 @@
     JasminBuilder jasminBuilder = new JasminBuilder();
     R8FullTestBuilder builder = testForR8(parameters.getBackend());
     for (int i = 0; i < 4; i++) {
-      jasminBuilder.addClass("TopLevel" + Integer.toString(i));
+      jasminBuilder.addClass("TopLevel" + i);
     }
     for (int i = 0; i < 4; i++) {
-      jasminBuilder.addClass("p1/SecondLevel" + Integer.toString(i));
+      jasminBuilder.addClass("p1/SecondLevel" + i);
     }
     for (int i = 0; i < 4; i++) {
-      jasminBuilder.addClass("p1/p2/ThirdLevel" + Integer.toString(i));
+      jasminBuilder.addClass("p1/p2/ThirdLevel" + i);
     }
     for (int i = 0; i < 4; i++) {
-      jasminBuilder.addClass("p2/SecondLevel" + Integer.toString(i));
+      jasminBuilder.addClass("p2/SecondLevel" + i);
     }
     builder.addProgramClassFileData(jasminBuilder.buildClasses());
     Set<String> usedDescriptors = new HashSet<>();
@@ -84,7 +84,7 @@
     JasminBuilder jasminBuilder = new JasminBuilder();
     R8FullTestBuilder builder = testForR8(parameters.getBackend());
     for (int i = 0; i < 26 * 2; i++) {
-      jasminBuilder.addClass("TestClass" + Integer.toString(i));
+      jasminBuilder.addClass("TestClass" + i);
     }
     builder.addProgramClassFileData(jasminBuilder.buildClasses());
     Set<String> usedNames = new HashSet<>();
diff --git a/src/test/java/com/android/tools/r8/naming/ClassObfuscationDictionaryDuplicateTest.java b/src/test/java/com/android/tools/r8/naming/ClassObfuscationDictionaryDuplicateTest.java
index e0ef67d..4683db2 100644
--- a/src/test/java/com/android/tools/r8/naming/ClassObfuscationDictionaryDuplicateTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ClassObfuscationDictionaryDuplicateTest.java
@@ -5,8 +5,9 @@
 package com.android.tools.r8.naming;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -16,8 +17,6 @@
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import java.io.IOException;
 import java.nio.file.Path;
-import java.util.HashSet;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -51,16 +50,11 @@
   public void test() throws IOException, CompilationFailedException, ExecutionException {
     Path dictionary = temp.getRoot().toPath().resolve("dictionary.txt");
     FileUtils.writeTextFile(dictionary, "a");
-
-    Set<String> finalNames = new HashSet<>();
-    finalNames.add(A.class.getPackage().getName() + ".a");
-    finalNames.add(B.class.getPackage().getName() + ".b");
-
     testForR8(parameters.getBackend())
         .addProgramClasses(A.class, B.class, C.class)
-        .noTreeShaking()
         .addKeepRules("-classobfuscationdictionary " + dictionary.toString())
         .addKeepMainRule(C.class)
+        .addKeepClassRulesWithAllowObfuscation(A.class, B.class)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), C.class)
         .assertSuccessWithOutput("HELLO WORLD!")
@@ -68,11 +62,12 @@
             inspector -> {
               ClassSubject clazzA = inspector.clazz(A.class);
               assertThat(clazzA, isPresent());
-              assertTrue(finalNames.contains(clazzA.getFinalName()));
-              finalNames.remove(clazzA.getFinalName());
               ClassSubject clazzB = inspector.clazz(B.class);
               assertThat(clazzB, isPresent());
-              assertTrue(finalNames.contains(clazzB.getFinalName()));
+              assertEquals(
+                  clazzA.getDexProgramClass().type.getPackageName(),
+                  clazzB.getDexProgramClass().type.getPackageName());
+              assertNotEquals(clazzA.getFinalName(), clazzB.getFinalName());
             });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java b/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
index 6804b54..bb7e06d 100644
--- a/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
+++ b/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
@@ -50,6 +50,7 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepClassRulesWithAllowObfuscation(A.class)
         .addKeepMainRule(Main.class)
+        .addKeepPackageNamesRule(Main.class.getPackage())
         .addKeepRules("-classobfuscationdictionary " + dictionary.toString())
         .applyIf(dontUseMixedCase, b -> b.addKeepRules("-dontusemixedcaseclassnames"))
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java b/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
index f72abf5..bb73c3f 100644
--- a/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
@@ -10,6 +10,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
+import com.android.tools.r8.ProguardVersion;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.naming.keeppackagenames.Top;
@@ -47,6 +48,7 @@
       assertEquals(
           getPackageNameFromDescriptor(top.getOriginalDescriptor()),
           getPackageNameFromDescriptor(top.getFinalDescriptor()));
+      assertEquals(PACKAGE_NAME, getPackageNameFromDescriptor(top.getFinalDescriptor()));
 
       ClassSubject sub = inspector.clazz(SubClass.class);
       assertThat(sub, isPresentAndRenamed());
@@ -55,13 +57,13 @@
           assertNotEquals(
               getPackageNameFromDescriptor(sub.getOriginalDescriptor()),
               getPackageNameFromDescriptor(sub.getFinalDescriptor()));
-          assertThat(
-              getPackageNameFromDescriptor(sub.getFinalDescriptor()), containsString(PACKAGE_NAME));
           break;
         case DOUBLE_ASTERISKS:
           assertEquals(
               getPackageNameFromDescriptor(sub.getOriginalDescriptor()),
               getPackageNameFromDescriptor(sub.getFinalDescriptor()));
+          assertThat(
+              getPackageNameFromDescriptor(sub.getFinalDescriptor()), containsString(PACKAGE_NAME));
           break;
       }
     }
@@ -80,7 +82,7 @@
 
   @Test
   public void testProguard() throws Exception {
-    testForProguard()
+    testForProguard(ProguardVersion.V6_0_1)
         .addProgramClasses(CLASSES)
         .addKeepAllClassesRuleWithAllowObfuscation()
         .addKeepRules(config.getKeepRule())
diff --git a/src/test/java/com/android/tools/r8/naming/MinificationMixedCaseAndNumbersTest.java b/src/test/java/com/android/tools/r8/naming/MinificationMixedCaseAndNumbersTest.java
index f27f20f..5c050a6 100644
--- a/src/test/java/com/android/tools/r8/naming/MinificationMixedCaseAndNumbersTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinificationMixedCaseAndNumbersTest.java
@@ -34,7 +34,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public MinificationMixedCaseAndNumbersTest(TestParameters parameters) {
@@ -55,8 +55,9 @@
         .addInnerClasses(MinificationMixedCaseAndNumbersTest.class)
         .addKeepMainRule(Main.class)
         .noTreeShaking()
-        .addKeepRules("-dontusemixedcaseclassnames")
-        .setMinApi(parameters.getRuntime())
+        .addKeepRules(
+            "-dontusemixedcaseclassnames", "-keeppackagenames com.android.tools.r8.naming")
+        .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
         .inspect(
             inspector -> {
diff --git a/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPackagePrivateMemberTest.java b/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPackagePrivateMemberTest.java
new file mode 100644
index 0000000..8064520
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPackagePrivateMemberTest.java
@@ -0,0 +1,92 @@
+// 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.naming;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MinifyPackageWithKeepToPackagePrivateMemberTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public MinifyPackageWithKeepToPackagePrivateMemberTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClassFileData(
+            transformer(A.class).removeInnerClasses().transform(),
+            transformer(ReflectiveCallerOfA.class).removeInnerClasses().transform(),
+            transformer(Main.class).removeInnerClasses().transform())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Hello World!", "Hello World!");
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(A.class).removeInnerClasses().transform(),
+            transformer(ReflectiveCallerOfA.class).removeInnerClasses().transform(),
+            transformer(Main.class).removeInnerClasses().transform())
+        .addKeepMainRule(Main.class)
+        .addKeepClassAndMembersRulesWithAllowObfuscation(A.class)
+        .addKeepRules("-keepclassmembernames class ** { *; }")
+        .addKeepRules(
+            "-identifiernamestring class "
+                + ReflectiveCallerOfA.class.getTypeName()
+                + " { java.lang.String className; }")
+        .enableInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Hello World!", "Hello World!");
+  }
+
+  static class A {
+
+    A() {}
+
+    String foo = "Hello World!";
+
+    void foo() {
+      System.out.println("Hello World!");
+    }
+  }
+
+  public static class ReflectiveCallerOfA {
+
+    private static String className =
+        "com.android.tools.r8.naming.MinifyPackageWithKeepToPackagePrivateMemberTest$A";
+
+    @NeverInline
+    public static void callA() throws Exception {
+      Class<?> aClass = Class.forName(className);
+      Object o = aClass.getDeclaredConstructor().newInstance();
+      System.out.println(aClass.getDeclaredField("foo").get(o));
+      aClass.getDeclaredMethod("foo").invoke(o);
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) throws Exception {
+      ReflectiveCallerOfA.callA();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPublicMemberTest.java b/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPublicMemberTest.java
new file mode 100644
index 0000000..240506d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPublicMemberTest.java
@@ -0,0 +1,129 @@
+// 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.naming;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MinifyPackageWithKeepToPublicMemberTest extends TestBase {
+
+  private final TestParameters parameters;
+  private final boolean minify;
+  private final String[] EXPECTED = new String[] {"Hello World!", "Hello World!"};
+
+  @Parameters(name = "{0}, minifyA: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+  }
+
+  public MinifyPackageWithKeepToPublicMemberTest(TestParameters parameters, boolean minify) {
+    this.parameters = parameters;
+    this.minify = minify;
+  }
+
+  @Test
+  public void testRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClassFileData(
+            transformer(A.class).removeInnerClasses().transform(),
+            transformer(ReflectiveCallerOfA.class).removeInnerClasses().transform(),
+            transformer(Main.class).removeInnerClasses().transform())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(A.class).removeInnerClasses().transform(),
+            transformer(ReflectiveCallerOfA.class).removeInnerClasses().transform(),
+            transformer(Main.class).removeInnerClasses().transform())
+        .addKeepMainRule(Main.class)
+        .applyIf(
+            minify,
+            builder -> builder.addKeepClassAndMembersRulesWithAllowObfuscation(A.class),
+            builder -> builder.addKeepClassAndMembersRules(A.class))
+        .addKeepRules("-keepclassmembernames class ** { *; }")
+        .addKeepRules(
+            "-identifiernamestring class "
+                + ReflectiveCallerOfA.class.getTypeName()
+                + " { java.lang.String className; }")
+        .enableInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject aClazz = inspector.clazz(A.class);
+              assertThat(aClazz, isPresentAndRenamed(minify));
+              ClassSubject reflectiveCallerOfAClass = inspector.clazz(ReflectiveCallerOfA.class);
+              assertThat(reflectiveCallerOfAClass, isPresentAndRenamed());
+              ClassSubject mainClass = inspector.clazz(Main.class);
+              assertThat(mainClass, isPresentAndNotRenamed());
+              assertNotEquals(
+                  mainClass.getDexProgramClass().type.getPackageDescriptor(),
+                  reflectiveCallerOfAClass.getDexProgramClass().type.getPackageDescriptor());
+              if (minify) {
+                assertEquals(
+                    aClazz.getDexProgramClass().type.getPackageDescriptor(),
+                    reflectiveCallerOfAClass.getDexProgramClass().type.getPackageDescriptor());
+              } else {
+                assertNotEquals(
+                    aClazz.getDexProgramClass().type.getPackageDescriptor(),
+                    reflectiveCallerOfAClass.getDexProgramClass().type.getPackageDescriptor());
+              }
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  public static class A {
+
+    public A() {}
+
+    public String foo = "Hello World!";
+
+    public void foo() {
+      System.out.println("Hello World!");
+    }
+  }
+
+  public static class ReflectiveCallerOfA {
+
+    private static String className =
+        "com.android.tools.r8.naming.MinifyPackageWithKeepToPublicMemberTest$A";
+
+    @NeverInline
+    public static void callA() throws Exception {
+      Class<?> aClass = Class.forName(className);
+      Object o = aClass.getDeclaredConstructor().newInstance();
+      System.out.println(aClass.getDeclaredField("foo").get(o));
+      aClass.getDeclaredMethod("foo").invoke(o);
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) throws Exception {
+      ReflectiveCallerOfA.callA();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
index 66ec3bb..9079f61 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
@@ -238,9 +238,9 @@
         b.getDexProgramClass().getType().getPackageName());
 
     ClassSubject sub_a = inspector.clazz("naming044.sub.SubA");
-    assertEquals(2, countPackageDepth(sub_a));
+    assertEquals(1, countPackageDepth(sub_a));
     ClassSubject sub_b = inspector.clazz("naming044.sub.SubB");
-    assertEquals(2, countPackageDepth(sub_b));
+    assertEquals(1, countPackageDepth(sub_b));
     assertEquals(
         sub_a.getDexProgramClass().getType().getPackageName(),
         sub_b.getDexProgramClass().getType().getPackageName());
@@ -327,9 +327,9 @@
 
     // All packages are renamed somehow. Need to check package hierarchy is consistent.
     ClassSubject aa = inspector.clazz("naming101.a.a");
-    assertEquals(2, countPackageDepth(aa));
+    assertEquals(1, countPackageDepth(aa));
     ClassSubject abc = inspector.clazz("naming101.a.b.c");
-    assertEquals(3, countPackageDepth(abc));
+    assertEquals(1, countPackageDepth(abc));
 
     // naming101.a/a; -> La/a/a; --prefix--> La/a
     // naming101.a/b/c; -> La/a/a/a; --prefix--> La/a/a --prefix--> La/a
@@ -356,14 +356,20 @@
         ba.getDexProgramClass().getType().getPackageName(),
         bb.getDexProgramClass().getType().getPackageName());
 
-    // All other classes can be repackaged to naming101.a, but naming101.a.a exists to make a name
-    // conflict. Thus, those should not be renamed to 'a'.
-    List<String> klasses = ImmutableList.of("naming101.c", "naming101.d", "naming101.a.b.c");
+    // We cannot repackage c or d since these have package-private members and a
+    // keep,allowobfuscation. For us to be able to repackage them, we have to use
+    // -allowaccesmodification.
+    List<String> klasses = ImmutableList.of("naming101.c", "naming101.d");
     for (String klass : klasses) {
       ClassSubject k = inspector.clazz(klass);
-      assertEquals("naming101.a", k.getDexProgramClass().getType().getPackageName());
-      assertNotEquals("naming101.a.a", k.getFinalName());
+      assertNotEquals("naming101.a", k.getDexProgramClass().getType().getPackageName());
     }
+
+    // All other classes can be repackaged to naming101.a, but naming101.a.a exists to make a name
+    // conflict. Thus, those should not be renamed to 'a'.
+    ClassSubject namingAbc = inspector.clazz("naming101.a.b.c");
+    assertEquals("naming101.a", namingAbc.getDexProgramClass().getType().getPackageName());
+    assertNotEquals("naming101.a.a", namingAbc.getFinalName());
   }
 
   private static void test101_rule104(CodeInspector inspector) {
@@ -411,11 +417,12 @@
     ClassSubject topD = inspector.clazz("naming101.d");
     assertEquals("naming101", topD.getDexProgramClass().getType().getPackageName());
 
-    // Due to the keep rule for naming101.c, package prefix naming101 is reserved.
-    // That is, every renamed class should have naming101 as parent package prefix.
-    for (String klass : klasses) {
-      ClassSubject t = inspector.clazz(klass);
-      assertTrue(t.getFinalName().startsWith("naming101."));
-    }
+    // The remaining classes are in subpackages of naming101 and will therefore not have
+    // package-private access to namin101.c
+    ClassSubject subAC = inspector.clazz("naming101.a.c");
+    assertEquals(1, countPackageDepth(subAC));
+
+    ClassSubject subABC = inspector.clazz("naming101.a.b.c");
+    assertEquals(1, countPackageDepth(subABC));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/PackageObfuscationDictionaryDuplicateTest.java b/src/test/java/com/android/tools/r8/naming/PackageObfuscationDictionaryDuplicateTest.java
index 133e607..0ac480f 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageObfuscationDictionaryDuplicateTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageObfuscationDictionaryDuplicateTest.java
@@ -57,9 +57,9 @@
         .inspect(
             inspector -> {
               ClassSubject clazzTop = inspector.clazz(Top.class);
-              assertTrue(clazzTop.getFinalName().endsWith(".a.a"));
+              assertTrue(clazzTop.getFinalName().endsWith("a.a"));
               ClassSubject clazzA = inspector.clazz(A.class);
-              assertTrue(clazzA.getFinalName().endsWith(".b.a"));
+              assertTrue(clazzA.getFinalName().endsWith("b.a"));
             });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/PackagePrivateAllowAccessModificationPackageTest.java b/src/test/java/com/android/tools/r8/naming/PackagePrivateAllowAccessModificationPackageTest.java
index 473df64..4be6559 100644
--- a/src/test/java/com/android/tools/r8/naming/PackagePrivateAllowAccessModificationPackageTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackagePrivateAllowAccessModificationPackageTest.java
@@ -53,10 +53,6 @@
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(
-            options -> {
-              options.enablePackagePrivateAwarePublicization = true;
-            })
         .compile()
         .inspect(
             inspector -> {
@@ -64,8 +60,7 @@
               assertThat(clazz, isPresentAndRenamed());
             })
         .run(parameters.getRuntime(), Main.class)
-        // TODO(b/172496438): This should not fail.
-        .assertFailureWithErrorThatThrows(IllegalAccessError.class);
+        .assertSuccessWithOutputLines(EXPECTED);
   }
 
   @NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java b/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
index f662aa6..696704f 100644
--- a/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.naming.b155249069.package_b.A;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import java.io.IOException;
@@ -29,6 +30,8 @@
   private final TestParameters parameters;
   private final boolean dontUseMixedCase;
 
+  private final String renamedATypeName = "Testpackage.A";
+
   @Parameters(name = "{0}, dontusemixedcaseclassnames: {1}")
   public static List<Object[]> data() {
     return buildParameters(
@@ -45,12 +48,22 @@
   public void testR8() throws ExecutionException, CompilationFailedException, IOException {
     Path packageDictionary = temp.getRoot().toPath().resolve("packagedictionary.txt");
     // Suggest the name 'a' for the package, to force a collision with A.A.
-    FileUtils.writeTextFile(packageDictionary, "a");
+    FileUtils.writeTextFile(packageDictionary, "testpackage");
     testForR8(parameters.getBackend())
-        .addProgramClasses(Main.class, com.android.tools.r8.naming.b155249069.A.A.class, A.class)
+        .addProgramClasses(A.class)
+        .addProgramClassFileData(
+            transformer(Main.class)
+                .replaceClassDescriptorInMethodInstructions(
+                    DescriptorUtils.javaTypeToDescriptor(
+                        com.android.tools.r8.naming.b155249069.A.A.class.getTypeName()),
+                    DescriptorUtils.javaTypeToDescriptor(renamedATypeName))
+                .transform(),
+            transformer(com.android.tools.r8.naming.b155249069.A.A.class)
+                .setClassDescriptor(DescriptorUtils.javaTypeToDescriptor(renamedATypeName))
+                .transform())
         .setMinApi(parameters.getApiLevel())
-        // Keep A.A such that the package A is kept.
-        .addKeepClassRules(com.android.tools.r8.naming.b155249069.A.A.class)
+        // Keep testpackage.A such that the package A is kept.
+        .addKeepClassRules(renamedATypeName)
         .addKeepClassRulesWithAllowObfuscation(A.class)
         .addKeepMainRule(Main.class)
         .addKeepRules("-packageobfuscationdictionary " + packageDictionary.toString())
@@ -59,8 +72,7 @@
         .assertSuccessWithOutputLines("A.A.foo()", "package_b.B.foo()")
         .inspect(
             inspector -> {
-              ClassSubject aSubject =
-                  inspector.clazz(com.android.tools.r8.naming.b155249069.A.A.class);
+              ClassSubject aSubject = inspector.clazz(renamedATypeName);
               ClassSubject bSubject = inspector.clazz(A.class);
               if (dontUseMixedCase) {
                 assertNotEquals(
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
index 63201fa..df0bfa6 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
@@ -4,12 +4,14 @@
 
 package com.android.tools.r8.repackage;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -50,12 +52,16 @@
         .inspect(
             inspector -> {
               // Find the generated lambda class
-              assertThat(
-                  ClassWithLambda.class,
-                  isRepackagedIf(inspector, repackage && parameters.isDexRuntime()));
               if (!parameters.isDexRuntime()) {
+                assertThat(ClassWithLambda.class, isNotRepackaged(inspector));
                 return;
               }
+              if (repackage) {
+                assertThat(ClassWithLambda.class, isRepackaged(inspector));
+              } else {
+                ClassSubject classWithLambdaSubject = inspector.clazz(ClassWithLambda.class);
+                assertThat(classWithLambdaSubject, isPresentAndRenamed());
+              }
               inspector.forAllClasses(
                   clazz -> {
                     if (clazz.isSynthesizedJavaLambdaClass()) {
diff --git a/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java b/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
index 617676f..c5c0859 100644
--- a/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
@@ -24,7 +24,7 @@
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
   }
 
   public MissingInterfaceTest(TestParameters parameters) {
@@ -39,6 +39,7 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(TestClassForB112849320.class)
         .addOptionsModification(options -> options.enableInlining = false)
+        .addKeepPackageNamesRule(GoingToBeMissed.class.getPackage())
         .compile()
         .addRunClasspathFiles(
             buildOnDexRuntime(