Merge changes Ieff6fd20,I16a59957

* changes:
  Use original static modifier when evaluating -if rules
  Use original final modifier when evaluating -if rules
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index ebeae02..63c1cde 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -45,11 +45,12 @@
     return NAMES;
   }
 
-  protected int flags;
-  protected boolean isPublicized = false;
+  protected int originalFlags;
+  protected int modifiedFlags;
 
-  protected AccessFlags(int flags) {
-    this.flags = flags;
+  protected AccessFlags(int originalFlags, int modifiedFlags) {
+    this.originalFlags = originalFlags;
+    this.modifiedFlags = modifiedFlags;
   }
 
   public abstract T copy();
@@ -57,10 +58,7 @@
   public abstract T self();
 
   public int materialize() {
-    if (isPromotedToPublic()) {
-      return ((flags | Constants.ACC_PUBLIC) & ~Constants.ACC_PROTECTED) & ~Constants.ACC_PRIVATE;
-    }
-    return flags;
+    return modifiedFlags;
   }
 
   public abstract int getAsCfAccessFlags();
@@ -68,21 +66,21 @@
   public abstract int getAsDexAccessFlags();
 
   public final int getOriginalCfAccessFlags() {
-    return flags;
+    return originalFlags;
   }
 
   @Override
   public boolean equals(Object object) {
     if (object instanceof AccessFlags) {
       AccessFlags other = (AccessFlags) object;
-      return flags == other.flags && isPublicized == other.isPublicized;
+      return originalFlags == other.originalFlags && modifiedFlags == other.modifiedFlags;
     }
     return false;
   }
 
   @Override
   public int hashCode() {
-    return (flags << 1) | (isPublicized ? 1 : 0);
+    return originalFlags | modifiedFlags;
   }
 
   public boolean isMoreVisibleThan(AccessFlags other) {
@@ -109,7 +107,7 @@
   }
 
   public boolean isPublic() {
-    return isSet(Constants.ACC_PUBLIC) || isPromotedToPublic();
+    return isSet(Constants.ACC_PUBLIC);
   }
 
   public void setPublic() {
@@ -122,7 +120,7 @@
   }
 
   public boolean isPrivate() {
-    return isSet(Constants.ACC_PRIVATE) && !isPromotedToPublic();
+    return isSet(Constants.ACC_PRIVATE);
   }
 
   public void setPrivate() {
@@ -135,7 +133,7 @@
   }
 
   public boolean isProtected() {
-    return isSet(Constants.ACC_PROTECTED) && !isPromotedToPublic();
+    return isSet(Constants.ACC_PROTECTED);
   }
 
   public void setProtected() {
@@ -179,35 +177,56 @@
     unset(Constants.ACC_SYNTHETIC);
   }
 
-  public boolean isPromotedToPublic() {
-    return isPublicized;
+  public void promoteToFinal() {
+    promote(Constants.ACC_FINAL);
   }
 
-  public T setPromotedToPublic(boolean isPublicized) {
-    this.isPublicized = isPublicized;
-    return self();
+  public void demoteFromFinal() {
+    demote(Constants.ACC_FINAL);
+  }
+
+  public boolean isPromotedToPublic() {
+    return isPromoted(Constants.ACC_PUBLIC);
   }
 
   public void promoteToPublic() {
-    isPublicized = true;
+    demote(Constants.ACC_PRIVATE | Constants.ACC_PROTECTED);
+    promote(Constants.ACC_PUBLIC);
   }
 
-  public void unsetPromotedToPublic() {
-    isPublicized = false;
+  public void promoteToStatic() {
+    promote(Constants.ACC_STATIC);
+  }
+
+  private boolean wasSet(int flag) {
+    return (originalFlags & flag) != 0;
   }
 
   protected boolean isSet(int flag) {
-    return (flags & flag) != 0;
+    return (modifiedFlags & flag) != 0;
   }
 
   protected void set(int flag) {
-    flags |= flag;
+    originalFlags |= flag;
+    modifiedFlags |= flag;
   }
 
   protected void unset(int flag) {
-    flags &= ~flag;
+    originalFlags &= ~flag;
+    modifiedFlags &= ~flag;
   }
 
+  protected boolean isPromoted(int flag) {
+    return !wasSet(flag) && isSet(flag);
+  }
+
+  protected void promote(int flag) {
+    modifiedFlags |= flag;
+  }
+
+  protected void demote(int flag) {
+    modifiedFlags &= ~flag;
+  }
 
   public String toSmaliString() {
     return toStringInternal(true);
diff --git a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
index 6c7caf9..0c96120 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
@@ -50,7 +50,11 @@
   }
 
   private ClassAccessFlags(int flags) {
-    super(flags);
+    this(flags, flags);
+  }
+
+  private ClassAccessFlags(int originalFlags, int modifiedFlags) {
+    super(originalFlags, modifiedFlags);
   }
 
   public static ClassAccessFlags fromSharedAccessFlags(int access) {
@@ -70,7 +74,7 @@
 
   @Override
   public ClassAccessFlags copy() {
-    return new ClassAccessFlags(flags).setPromotedToPublic(isPromotedToPublic());
+    return new ClassAccessFlags(originalFlags, modifiedFlags);
   }
 
   @Override
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 5aa2ee4..44294db 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -645,7 +645,7 @@
     // for the forwarding method, as the forwarding method will copy the access flags from this,
     // and if different forwarding methods are created in different subclasses the first could be
     // final.
-    accessFlags.unsetFinal();
+    accessFlags.demoteFromFinal();
     DexMethod newMethod = itemFactory.createMethod(holder.type, method.proto, method.name);
     Invoke.Type type = accessFlags.isStatic() ? Invoke.Type.STATIC : Invoke.Type.SUPER;
     Builder builder = builder(this);
@@ -685,7 +685,8 @@
   public DexEncodedMethod toStaticMethodWithoutThis() {
     checkIfObsolete();
     assert !accessFlags.isStatic();
-    Builder builder = builder(this).setStatic().unsetOptimizationInfo().withoutThisParameter();
+    Builder builder =
+        builder(this).promoteToStatic().unsetOptimizationInfo().withoutThisParameter();
     setObsolete();
     return builder.build();
   }
@@ -1255,8 +1256,8 @@
       this.method = method;
     }
 
-    public Builder setStatic() {
-      this.accessFlags.setStatic();
+    public Builder promoteToStatic() {
+      this.accessFlags.promoteToStatic();
       return this;
     }
 
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java b/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
index e940269..bb39765 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
@@ -37,12 +37,16 @@
   }
 
   private FieldAccessFlags(int flags) {
-    super(flags);
+    this(flags, flags);
+  }
+
+  private FieldAccessFlags(int originalFlags, int modifiedFlags) {
+    super(originalFlags, modifiedFlags);
   }
 
   @Override
   public FieldAccessFlags copy() {
-    return new FieldAccessFlags(flags).setPromotedToPublic(isPromotedToPublic());
+    return new FieldAccessFlags(originalFlags, modifiedFlags);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
index ca507b7..2173ed0 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
@@ -54,12 +54,16 @@
   }
 
   private MethodAccessFlags(int flags) {
-    super(flags);
+    this(flags, flags);
+  }
+
+  private MethodAccessFlags(int originalFlags, int modifiedFlags) {
+    super(originalFlags, modifiedFlags);
   }
 
   @Override
   public MethodAccessFlags copy() {
-    return new MethodAccessFlags(flags).setPromotedToPublic(isPromotedToPublic());
+    return new MethodAccessFlags(originalFlags, modifiedFlags);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 6ba9b6a..4f335a6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -85,7 +85,7 @@
 
         MethodAccessFlags newFlags = virtual.accessFlags.copy();
         newFlags.unsetBridge();
-        newFlags.setStatic();
+        newFlags.promoteToStatic();
         DexCode dexCode = code.asDexCode();
         // We cannot name the parameter "this" because the debugger may omit it due to the method
         // actually being static. Instead we prepend it with a special character.
@@ -124,8 +124,7 @@
       MethodAccessFlags originalFlags = direct.accessFlags;
       MethodAccessFlags newFlags = originalFlags.copy();
       if (originalFlags.isPrivate()) {
-        newFlags.unsetPrivate();
-        newFlags.setPublic();
+        newFlags.promoteToPublic();
       }
 
       DexMethod oldMethod = direct.method;
@@ -143,7 +142,7 @@
           assert !rewriter.factory.isClassConstructor(oldMethod)
               : "Unexpected private constructor " + direct.toSourceString()
               + " in " + iface.origin;
-          newFlags.setStatic();
+          newFlags.promoteToStatic();
 
           DexMethod companionMethod = rewriter.privateAsMethodOfCompanionClass(oldMethod);
 
diff --git a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
index b59e3e9..72fc987 100644
--- a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
@@ -128,7 +128,7 @@
         return false;
       }
       lenseBuilder.add(encodedMethod.method);
-      accessFlags.setFinal();
+      accessFlags.promoteToFinal();
       accessFlags.promoteToPublic();
       // Although the current method became public, it surely has the single virtual target.
       encodedMethod.method.setSingleVirtualMethodCache(
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 6cf0da0..f502692 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -92,7 +92,7 @@
             // corresponding methods in this class. This might happen if we only keep this
             // class around for its constants.
             // For now, we remove the final flag to still be able to mark it abstract.
-            clazz.accessFlags.unsetFinal();
+            clazz.accessFlags.demoteFromFinal();
           }
           clazz.accessFlags.setAbstract();
         }
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 45ca1af..b9f7554 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1214,7 +1214,6 @@
         // The bridge is now the public method serving the role of the original method, and should
         // reflect that this method was publicized.
         assert bridge.accessFlags.isPromotedToPublic();
-        method.accessFlags.unsetPromotedToPublic();
       }
       return bridge;
     }
@@ -1409,7 +1408,6 @@
 
   private static void makePrivate(DexEncodedMethod method) {
     assert !method.accessFlags.isAbstract();
-    method.accessFlags.unsetPromotedToPublic();
     method.accessFlags.unsetPublic();
     method.accessFlags.unsetProtected();
     method.accessFlags.setPrivate();
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/accessrelaxation/IfRuleWithAccessRelaxation.java b/src/test/java/com/android/tools/r8/shaking/ifrule/accessrelaxation/IfRuleWithAccessRelaxation.java
deleted file mode 100644
index cf6d7c0..0000000
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/accessrelaxation/IfRuleWithAccessRelaxation.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.ifrule.accessrelaxation;
-
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-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 IfRuleWithAccessRelaxation extends TestBase {
-
-  private final Backend backend;
-
-  public IfRuleWithAccessRelaxation(Backend backend) {
-    this.backend = backend;
-  }
-
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return Backend.values();
-  }
-
-  @Test
-  public void r8Test() throws Exception {
-    CodeInspector inspector =
-        testForR8(backend)
-            .addInnerClasses(IfRuleWithAccessRelaxation.class)
-            .addKeepRules(
-                "-keep class " + TestClass.class.getTypeName() + " { int field; void method(); }",
-                "-if class " + TestClass.class.getTypeName() + " { protected int field; }",
-                "-keep class " + Unused1.class.getTypeName(),
-                "-if class " + TestClass.class.getTypeName() + " { protected void method(); }",
-                "-keep class " + Unused2.class.getTypeName(),
-                "-allowaccessmodification")
-            .compile()
-            .inspector();
-
-    assertTrue(inspector.clazz(TestClass.class).isPublic());
-    assertTrue(inspector.clazz(TestClass.class).uniqueMethodWithName("method").isPublic());
-    assertTrue(inspector.clazz(TestClass.class).uniqueFieldWithName("field").isPublic());
-
-    assertThat(inspector.clazz(Unused1.class), isPresent());
-    assertThat(inspector.clazz(Unused2.class), isPresent());
-  }
-
-  protected static class TestClass {
-
-    protected int field = 42;
-
-    protected void method() {}
-  }
-
-  static class Unused1 {}
-
-  static class Unused2 {}
-}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/accessrelaxation/IfRuleWithAccessRelaxationTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/accessrelaxation/IfRuleWithAccessRelaxationTest.java
new file mode 100644
index 0000000..560ebd4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/accessrelaxation/IfRuleWithAccessRelaxationTest.java
@@ -0,0 +1,97 @@
+// 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.ifrule.accessrelaxation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isFinal;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+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 IfRuleWithAccessRelaxationTest extends TestBase {
+
+  private final Backend backend;
+
+  public IfRuleWithAccessRelaxationTest(Backend backend) {
+    this.backend = backend;
+  }
+
+  @Parameters(name = "Backend: {0}")
+  public static Backend[] data() {
+    return Backend.values();
+  }
+
+  @Test
+  public void r8Test() throws Exception {
+    CodeInspector inspector =
+        testForR8(backend)
+            .addInnerClasses(IfRuleWithAccessRelaxationTest.class)
+            .addKeepMainRule(TestClass.class)
+            .addKeepRules(
+                "-keep class " + TestClass.class.getTypeName() + " { int field; }",
+                "-if class " + TestClass.class.getTypeName() + " { protected int field; }",
+                "-keep class " + Unused1.class.getTypeName(),
+                "-if class " + TestClass.class.getTypeName() + " {",
+                "  private !final void privateMethod();",
+                "}",
+                "-keep class " + Unused2.class.getTypeName(),
+                "-if class " + TestClass.class.getTypeName() + " {",
+                "  protected void virtualMethod();",
+                "}",
+                "-keep class " + Unused3.class.getTypeName(),
+                "-allowaccessmodification")
+            .enableInliningAnnotations()
+            .compile()
+            .inspector();
+
+    assertTrue(inspector.clazz(TestClass.class).isPublic());
+    assertThat(inspector.clazz(TestClass.class).uniqueFieldWithName("field"), isPublic());
+    assertThat(
+        inspector.clazz(TestClass.class).uniqueMethodWithName("privateMethod"),
+        allOf(isPublic(), isFinal()));
+    assertThat(inspector.clazz(TestClass.class).uniqueMethodWithName("virtualMethod"), isPublic());
+
+    assertThat(inspector.clazz(Unused1.class), isPresent());
+    assertThat(inspector.clazz(Unused2.class), isPresent());
+    assertThat(inspector.clazz(Unused3.class), isPresent());
+  }
+
+  protected static class TestClass {
+
+    public static void main(String[] args) {
+      TestClass obj = new TestClass();
+      obj.privateMethod();
+      obj.virtualMethod();
+    }
+
+    protected int field = 42;
+
+    @NeverInline
+    private void privateMethod() {
+      System.out.println("In privateMethod()");
+    }
+
+    @NeverInline
+    protected void virtualMethod() {
+      System.out.println("In virtualMethod()");
+    }
+  }
+
+  static class Unused1 {}
+
+  static class Unused2 {}
+
+  static class Unused3 {}
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
new file mode 100644
index 0000000..a12620d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
@@ -0,0 +1,113 @@
+// Copyright (c) 2019, 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.ifrule.classstaticizer;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import java.util.List;
+import java.util.stream.Collectors;
+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 IfRuleWithClassStaticizerTest extends TestBase {
+
+  private final Backend backend;
+
+  @Parameters(name = "Backend: {0}")
+  public static Backend[] data() {
+    return Backend.values();
+  }
+
+  public IfRuleWithClassStaticizerTest(Backend backend) {
+    this.backend = backend;
+  }
+
+  @Test
+  public void test() throws Exception {
+    String expectedOutput = StringUtils.lines("In method()");
+
+    if (backend == Backend.CF) {
+      testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
+    }
+
+    CodeInspector inspector =
+        testForR8(backend)
+            .addInnerClasses(IfRuleWithClassStaticizerTest.class)
+            .addKeepMainRule(TestClass.class)
+            .addKeepRules(
+                "-if class " + StaticizerCandidate.Companion.class.getTypeName() + " {",
+                "  public !static void method();",
+                "}",
+                "-keep class " + Unused.class.getTypeName())
+            .enableInliningAnnotations()
+            .enableClassInliningAnnotations()
+            .run(TestClass.class)
+            .assertSuccessWithOutput(expectedOutput)
+            .inspector();
+
+    ClassSubject classSubject = inspector.clazz(StaticizerCandidate.class);
+    assertThat(classSubject, isPresent());
+
+    if (backend == Backend.CF) {
+      // The class staticizer is not enabled for CF.
+      assertThat(inspector.clazz(Unused.class), isPresent());
+    } else {
+      assert backend == Backend.DEX;
+
+      // There should be a static method on StaticizerCandidate after staticizing.
+      List<FoundMethodSubject> staticMethods =
+          classSubject.allMethods().stream()
+              .filter(method -> method.isStatic() && !method.isClassInitializer())
+              .collect(Collectors.toList());
+      assertEquals(1, staticMethods.size());
+      assertEquals(
+          "void " + StaticizerCandidate.Companion.class.getTypeName() + ".method()",
+          staticMethods.get(0).getOriginalSignature().toString());
+
+      // The Companion class should not be present after staticizing.
+      assertThat(inspector.clazz(StaticizerCandidate.Companion.class), not(isPresent()));
+
+      // TODO(b/122867080): The Unused class should be present due to the -if rule.
+      assertThat(inspector.clazz(Unused.class), not(isPresent()));
+    }
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      StaticizerCandidate.companion.method();
+    }
+  }
+
+  @NeverClassInline
+  static class StaticizerCandidate {
+
+    static final Companion companion = new Companion();
+
+    @NeverClassInline
+    static class Companion {
+
+      @NeverInline
+      public void method() {
+        System.out.println("In method()");
+      }
+    }
+  }
+
+  static class Unused {}
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
new file mode 100644
index 0000000..d86bc68
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -0,0 +1,105 @@
+// Copyright (c) 2019, 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.ifrule.interfacemethoddesugaring;
+
+import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isStatic;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+
+public class IfRuleWithInterfaceMethodDesugaringTest extends TestBase {
+
+  @Test
+  public void test() throws Exception {
+    String expectedOutput =
+        StringUtils.lines("In Interface.staticMethod()", "In Interface.virtualMethod()");
+
+    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
+
+    CodeInspector inspector =
+        testForR8(Backend.DEX)
+            .addInnerClasses(IfRuleWithInterfaceMethodDesugaringTest.class)
+            .addKeepMainRule(TestClass.class)
+            .addKeepRules(
+                "-if class " + Interface.class.getTypeName() + " {",
+                "  !public static void staticMethod();",
+                "}",
+                "-keep class " + Unused1.class.getTypeName(),
+                "-if class " + Interface.class.getTypeName() + " {",
+                "  !public !static void virtualMethod();",
+                "}",
+                "-keep class " + Unused2.class.getTypeName())
+            .enableInliningAnnotations()
+            .enableClassInliningAnnotations()
+            .enableMergeAnnotations()
+            .setMinApi(AndroidApiLevel.M)
+            .run(TestClass.class)
+            .assertSuccessWithOutput(expectedOutput)
+            .inspector();
+
+    ClassSubject classSubject =
+        inspector.clazz(Interface.class.getTypeName() + COMPANION_CLASS_NAME_SUFFIX);
+    assertThat(classSubject, isPresent());
+    assertEquals(2, classSubject.allMethods().size());
+
+    MethodSubject staticMethodSubject = classSubject.uniqueMethodWithName("staticMethod");
+    assertThat(staticMethodSubject, allOf(isPresent(), isPublic(), isStatic()));
+
+    // TODO(b/122867087): Should not be necessary to use `DEFAULT_METHOD_PREFIX`.
+    MethodSubject virtualMethodSubject =
+        classSubject.uniqueMethodWithName(DEFAULT_METHOD_PREFIX + "virtualMethod");
+    assertThat(virtualMethodSubject, allOf(isPresent(), isPublic(), isStatic()));
+
+    // TODO(b/122875545): The Unused class should be present due to the -if rule.
+    assertThat(inspector.clazz(Unused1.class), not(isPresent()));
+    assertThat(inspector.clazz(Unused2.class), not(isPresent()));
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      Interface.staticMethod();
+      new InterfaceImpl().virtualMethod();
+    }
+  }
+
+  @NeverClassInline
+  @NeverMerge
+  interface Interface {
+
+    @NeverInline
+    static void staticMethod() {
+      System.out.println("In Interface.staticMethod()");
+    }
+
+    @NeverInline
+    default void virtualMethod() {
+      System.out.println("In Interface.virtualMethod()");
+    }
+  }
+
+  @NeverClassInline
+  static class InterfaceImpl implements Interface {}
+
+  static class Unused1 {}
+
+  static class Unused2 {}
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index 8cd5cc7..11ee3af 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -102,7 +102,7 @@
   public MethodSubject uniqueMethodWithName(String name) {
     MethodSubject methodSubject = null;
     for (FoundMethodSubject candidate : allMethods()) {
-      if (candidate.getOriginalName().equals(name)) {
+      if (candidate.getOriginalName(false).equals(name)) {
         assert methodSubject == null;
         methodSubject = candidate;
       }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
index b2dff57..103ffb9 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
@@ -146,6 +146,28 @@
     };
   }
 
+  public static Matcher<MemberSubject> isStatic() {
+    return new TypeSafeMatcher<MemberSubject>() {
+      @Override
+      public boolean matchesSafely(final MemberSubject subject) {
+        return subject.isPresent() && subject.isStatic();
+      }
+
+      @Override
+      public void describeTo(final Description description) {
+        description.appendText(" present");
+      }
+
+      @Override
+      public void describeMismatchSafely(final MemberSubject subject, Description description) {
+        description
+            .appendText(type(subject) + " ")
+            .appendValue(name(subject))
+            .appendText(" was not");
+      }
+    };
+  }
+
   public static Matcher<Subject> isSynthetic() {
     return new TypeSafeMatcher<Subject>() {
       @Override
@@ -227,6 +249,28 @@
     };
   }
 
+  public static Matcher<MethodSubject> isFinal() {
+    return new TypeSafeMatcher<MethodSubject>() {
+      @Override
+      public boolean matchesSafely(final MethodSubject method) {
+        return method.isPresent() && method.isFinal();
+      }
+
+      @Override
+      public void describeTo(final Description description) {
+        description.appendText("is final");
+      }
+
+      @Override
+      public void describeMismatchSafely(final MethodSubject method, Description description) {
+        description
+            .appendText("method ")
+            .appendValue(method.getOriginalName())
+            .appendText(" was not");
+      }
+    };
+  }
+
   public static <T extends MemberSubject> Matcher<T> isPrivate() {
     return hasVisibility(Visibility.PRIVATE);
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MemberSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MemberSubject.java
index a95b6e6..af1fe14 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MemberSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MemberSubject.java
@@ -25,8 +25,22 @@
   public abstract Signature getFinalSignature();
 
   public String getOriginalName() {
+    return getOriginalName(true);
+  }
+
+  public String getOriginalName(boolean qualified) {
     Signature originalSignature = getOriginalSignature();
-    return originalSignature == null ? null : originalSignature.name;
+    if (originalSignature != null) {
+      String name = originalSignature.name;
+      if (!qualified) {
+        int index = name.lastIndexOf(".");
+        if (index >= 0) {
+          return name.substring(index + 1);
+        }
+      }
+      return name;
+    }
+    return null;
   }
 
   public String getFinalName() {