Only apply bottom-up propagation to methods without body.

Bug: 137938214, 133208961
Change-Id: Ib2946cedcd5bec4cb518a3100186787339f52844
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 3ae95b1..62b2fd9 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -306,6 +306,11 @@
       return;
     }
     for (DexEncodedMethod encodedMethod : clazz.virtualMethods()) {
+      // If the method has a body, it may have side effects. Don't do bottom-up propagation.
+      if (encodedMethod.hasCode()) {
+        assert !encodedMethod.shouldNotHaveCode();
+        continue;
+      }
       propagateAssumeRules(clazz.type, encodedMethod.method, subTypes, noSideEffects);
       propagateAssumeRules(clazz.type, encodedMethod.method, subTypes, assumedValues);
     }
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
index 93dc5c6..86a77a5 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
@@ -15,7 +15,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
-
 @RunWith(Parameterized.class)
 public class AssumenosideeffectsPropagationTest extends TestBase {
   private static final Class<?> MAIN = SubsUser.class;
@@ -159,21 +158,10 @@
     void verbose(String message);
   }
 
-  static class Base1 implements Itf {
-    @Override
-    public void info(String message) {
-      System.out.println("[Base1, info]: " + message);
-    }
-
-    @Override
-    public void debug(String message) {
-      System.out.println("[Base1, debug]: " + message);
-    }
-
-    @Override
-    public void verbose(String message) {
-      System.out.println("[Base1, verbose]: " + message);
-    }
+  static abstract class Base1 implements Itf {
+    public abstract void info(String message);
+    public abstract void debug(String message);
+    public abstract void verbose(String message);
   }
 
   static class Sub1 extends Base1 {
@@ -183,6 +171,11 @@
     }
 
     @Override
+    public void debug(String message) {
+      System.out.println("[Base1, debug]: " + message);
+    }
+
+    @Override
     public void verbose(String message) {
       System.out.println("[Sub1, verbose]: " + message);
     }
@@ -195,12 +188,23 @@
     }
 
     @Override
+    public void debug(String message) {
+      System.out.println("[Base1, debug]: " + message);
+    }
+
+    @Override
     public void verbose(String message) {
       System.out.println("[Sub2, verbose]: " + message);
     }
   }
 
-  static class Base2 implements Itf {
+  static abstract class Base2 implements Itf {
+    public abstract void info(String message);
+    public abstract void debug(String message);
+    public abstract void verbose(String message);
+  }
+
+  static class AnotherSub1 extends Base2 {
     @Override
     public void info(String message) {
       System.out.println("[Base2, info]: " + message);
@@ -208,18 +212,6 @@
 
     @Override
     public void debug(String message) {
-      System.out.println("[Base2, debug]: " + message);
-    }
-
-    @Override
-    public void verbose(String message) {
-      System.out.println("[Base2, verbose]: " + message);
-    }
-  }
-
-  static class AnotherSub1 extends Base2 {
-    @Override
-    public void debug(String message) {
       System.out.println("[AnotherSub1, debug]: " + message);
     }
 
@@ -231,6 +223,11 @@
 
   static class AnotherSub2 extends Base2 {
     @Override
+    public void info(String message) {
+      System.out.println("[Base2, info]: " + message);
+    }
+
+    @Override
     public void debug(String message) {
       System.out.println("[AnotherSub2, debug]: " + message);
     }
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java
index e063df1..ba5da12 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java
@@ -50,10 +50,7 @@
       switch (this) {
         case SPECIFIC_RULES:
         case NON_SPECIFIC_RULES_WITH_EXTENDS:
-          // TODO(b/133208961): If DelegateSub1#debug is not explicitly defined, we would not
-          //   propagate the rule, and thus the output would
-          // return JVM_OUTPUT;
-          return OUTPUT_WITHOUT_MESSAGES;
+          return JVM_OUTPUT;
         default:
           throw new Unreachable();
       }
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
index 24edc40..8928015 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
@@ -92,8 +92,7 @@
           return StringUtils.lines(
               "Expect to catch RuntimeException",
               "[LibraryBase]: as long as LibraryBase is specified",
-              // TODO(b/137938214): Should we do synthetic propagation up to ProgramBase#debug() ?
-              // "[ProgramBase]: as long as ProgramBase is specified"
+              "[ProgramBase]: as long as ProgramBase is specified",
               "The end");
         case RULE_WITH_EXTENDS_LIB_BASE:
           return StringUtils.lines(
@@ -104,8 +103,7 @@
           return StringUtils.lines(
               "Expect to catch RuntimeException",
               "[LibraryBase]: as long as LibraryBase is specified",
-              // TODO(b/137938214): Should we do synthetic propagation up to ProgramBase#debug() ?
-              // "[ProgramBase]: as long as ProgramBase is specified"
+              "[ProgramBase]: as long as ProgramBase is specified",
               "The end");
       }
       throw new Unreachable();