Merge "Remove enclosing method attrs that reference pruned items."
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index f69251b..c76865e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -482,6 +482,12 @@
     enclosingMethod = null;
   }
 
+  public void removeEnclosingMethod(Predicate<EnclosingMethodAttribute> predicate) {
+    if (enclosingMethod != null && predicate.test(enclosingMethod)) {
+      enclosingMethod = null;
+    }
+  }
+
   public void clearInnerClasses() {
     innerClasses.clear();
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index c012898..6cf0da0 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -8,8 +8,10 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.EnclosingMethodAttribute;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.KeyedDexItem;
 import com.android.tools.r8.graph.PresortedComparable;
@@ -102,15 +104,44 @@
         clazz.setInstanceFields(reachableFields(clazz.instanceFields()));
         clazz.setStaticFields(reachableFields(clazz.staticFields()));
         clazz.removeInnerClasses(this::isAttributeReferencingPrunedType);
+        clazz.removeEnclosingMethod(this::isAttributeReferencingPrunedItem);
         usagePrinter.visited();
       }
     }
     return newClasses;
   }
 
+  private boolean isAttributeReferencingPrunedItem(EnclosingMethodAttribute attr) {
+    return
+        (attr.getEnclosingClass() != null
+            && !appInfo.liveTypes.contains(attr.getEnclosingClass()))
+        || (attr.getEnclosingMethod() != null
+            && !appInfo.liveMethods.contains(attr.getEnclosingMethod()));
+  }
+
   private boolean isAttributeReferencingPrunedType(InnerClassAttribute attr) {
-    return (attr.getInner() != null && !appInfo.liveTypes.contains(attr.getInner()))
-        || (attr.getOuter() != null && !appInfo.liveTypes.contains(attr.getOuter()));
+    if (!appInfo.liveTypes.contains(attr.getInner())) {
+      return true;
+    }
+    DexType context = attr.getOuter();
+    if (context == null) {
+      DexClass inner = appInfo.definitionFor(attr.getInner());
+      if (inner != null && inner.getEnclosingMethod() != null) {
+        EnclosingMethodAttribute enclosingMethodAttribute = inner.getEnclosingMethod();
+        if (enclosingMethodAttribute.getEnclosingClass() != null) {
+          context = enclosingMethodAttribute.getEnclosingClass();
+        } else {
+          DexMethod enclosingMethod = enclosingMethodAttribute.getEnclosingMethod();
+          if (!appInfo.liveMethods.contains(enclosingMethod)) {
+            // EnclosingMethodAttribute will be pruned as it references the pruned method.
+            // Hence, removal of the current InnerClassAttribute too.
+            return true;
+          }
+          context = enclosingMethod.getHolder();
+        }
+      }
+    }
+    return context == null || !appInfo.liveTypes.contains(context);
   }
 
   private <S extends PresortedComparable<S>, T extends KeyedDexItem<S>> int firstUnreachableIndex(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
index 9cc69fa..54f9df3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
@@ -263,7 +263,7 @@
         .addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
         .addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
     if (!enableMinification) {
-      builder.addKeepRules("-dontobfuscate");
+      builder.noMinification();
     }
     TestRunResult result =
         builder
@@ -284,7 +284,7 @@
         .addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
         .addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
     if (!enableMinification) {
-      builder.addKeepRules("-dontobfuscate");
+      builder.noMinification();
     }
     TestRunResult result =
         builder
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
index b75e4ee..5a9ca75 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
@@ -124,7 +124,7 @@
       "Inner",
       "Inner"
   );
-  private static final String OUTPUT_WITH_SHRUNK_ATTRIBUTE = StringUtils.lines(
+  private static final String OUTPUT_WITH_SHRUNK_ATTRIBUTES = StringUtils.lines(
       "Local_t03",
       "InnerLocal",
       "$",
@@ -211,7 +211,7 @@
         .addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
         .addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
     if (!enableMinification) {
-      builder.addKeepRules("-dontobfuscate");
+      builder.noMinification();
     }
     TestRunResult result =
         builder
@@ -231,12 +231,12 @@
         .addKeepRules("-keep,allowobfuscation class **.ClassGetSimpleName*")
         // See b/119471127: some old VMs are not resilient to broken attributes.
         // Comment out the following line to reproduce b/120130435
-        // then use OUTPUT_WITH_SHRUNK_ATTRIBUTE
+        // then use OUTPUT_WITH_SHRUNK_ATTRIBUTES
         .addKeepRules("-keep,allowobfuscation class **.Outer*")
         .addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
         .addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
     if (!enableMinification) {
-      builder.addKeepRules("-dontobfuscate");
+      builder.noMinification();
     }
     R8TestRunResult result =
         builder
diff --git a/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java b/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
index c14cef5..4e121a8 100644
--- a/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
@@ -49,6 +49,8 @@
   private final boolean enableMinification;
   private Collection<Path> classPaths;
   private static final String JAVA_OUTPUT = "-Returned-null-" + System.lineSeparator();
+  private static final String OUTPUT_WITH_SHRUNK_ATTRIBUTES =
+      "com.android.tools.r8.shaking.GetNameClass$1" + System.lineSeparator();
   private static final Class<?> MAIN = GetNameMain.class;
 
   @Parameterized.Parameters(name = "Backend: {0} minification: {1}")
@@ -88,18 +90,10 @@
         .addKeepRules("-keep class **.GetName*")
         .addKeepRules("-keepattributes InnerClasses,EnclosingMethod");
     if (!enableMinification) {
-      builder.addKeepRules("-dontobfuscate");
+      builder.noMinification();
     }
 
     R8TestRunResult result = builder.run(MAIN);
-    if (backend == Backend.DEX) {
-      if (ToolHelper.getDexVm().getVersion().isNewerThan(Version.V4_4_4)
-          && ToolHelper.getDexVm().getVersion().isOlderThanOrEqual(Version.V6_0_1)) {
-        result.assertFailureWithErrorThatMatches(containsString("IncompatibleClassChangeError"));
-        return;
-      }
-    }
-
-    result.assertSuccessWithOutput(JAVA_OUTPUT);
+    result.assertSuccessWithOutput(OUTPUT_WITH_SHRUNK_ATTRIBUTES);
   }
 }