Merge "Reserved parent package prefix should be reserved indeed."
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 39ca020..c363484 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -286,9 +286,15 @@
     if (state == null) {
       // Calculate the parent package prefix, e.g., La/b/c -> La/b
       String parentPackage = getParentPackagePrefix(prefix);
-      // 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);
+      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);
+      }
       // 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/test/examples/naming101/keep-rules-106.txt b/src/test/examples/naming101/keep-rules-106.txt
new file mode 100644
index 0000000..69c29dd
--- /dev/null
+++ b/src/test/examples/naming101/keep-rules-106.txt
@@ -0,0 +1,16 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This will dominate the whole package hierarchy.
+-keep class naming101.c {
+  *;
+}
+
+-keep,allowobfuscation class **.c {
+  *;
+}
+
+-keep,allowobfuscation class **.d {
+  *;
+}
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 5975483..877ffc0 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
@@ -26,6 +26,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -74,6 +75,7 @@
     inspections.put("naming101:keep-rules-005.txt", PackageNamingTest::test101_rule005);
     inspections.put("naming101:keep-rules-102.txt", PackageNamingTest::test101_rule102);
     inspections.put("naming101:keep-rules-104.txt", PackageNamingTest::test101_rule104);
+    inspections.put("naming101:keep-rules-106.txt", PackageNamingTest::test101_rule106);
 
     return createTests(tests, inspections);
   }
@@ -357,4 +359,31 @@
       assertNotEquals("naming101.a", getPackageNameFromDescriptor(renamedName));
     }
   }
+
+  private static void test101_rule106(DexItemFactory dexItemFactory, NamingLens naming) {
+    // Classes that end with either c or d will be kept and renamed.
+    List<String> klasses =
+        CLASSES_IN_NAMING101.stream()
+            .filter(className -> className.endsWith("c;") || className.endsWith("d;"))
+            .collect(Collectors.toList());
+    verifyUniqueNaming(dexItemFactory, naming, klasses);
+
+    // Check naming101.c is kept as-is.
+    DexType topC = dexItemFactory.createType("Lnaming101/c;");
+    assertEquals("Lnaming101/c;", naming.lookupDescriptor(topC).toSourceString());
+
+    // naming101.d accesses to a package-private, static field in naming101.c.
+    // Therefore, it should remain in the same package.
+    DexType topD = dexItemFactory.createType("Lnaming101/d;");
+    String renamedTopD = naming.lookupDescriptor(topD).toSourceString();
+    assertEquals("naming101", getPackageNameFromDescriptor(renamedTopD));
+
+    // 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) {
+      DexType t = dexItemFactory.createType(klass);
+      String rename = naming.lookupDescriptor(t).toSourceString();
+      assertTrue(rename.startsWith("Lnaming101/"));
+    }
+  }
 }