Merge "Avoid processing empty bridge methods in VisibilityBridgeRemover."
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
index 5847a80..ebf110e 100644
--- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.optimize.InvokeSingleTargetExtractor.InvokeKind;
 import com.google.common.collect.Sets;
@@ -28,7 +29,8 @@
   }
 
   private void identifyBridgeMethod(DexEncodedMethod method) {
-    if (method.accessFlags.isBridge()) {
+    MethodAccessFlags accessFlags = method.accessFlags;
+    if (accessFlags.isBridge() && !accessFlags.isAbstract()) {
       InvokeSingleTargetExtractor targetExtractor = new InvokeSingleTargetExtractor();
       method.getCode().registerCodeReferences(targetExtractor);
       DexMethod target = targetExtractor.getTarget();
@@ -36,11 +38,11 @@
       // javac-generated visibility forward bridge method has same descriptor (name, signature and
       // return type).
       if (target != null && target.hasSameProtoAndName(method.method)) {
-        assert !method.accessFlags.isPrivate() && !method.accessFlags.isConstructor();
+        assert !accessFlags.isPrivate() && !accessFlags.isConstructor();
         if (kind == InvokeKind.SUPER) {
           // This is a visibility forward, so check for the direct target.
-          DexEncodedMethod targetMethod
-              = appInfo.resolveMethod(target.getHolder(), target).asSingleTarget();
+          DexEncodedMethod targetMethod =
+              appInfo.resolveMethod(target.getHolder(), target).asSingleTarget();
           if (targetMethod != null && targetMethod.accessFlags.isPublic()) {
             if (Log.ENABLED) {
               Log.info(getClass(), "Removing visibility forwarding %s -> %s", method.method,
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/EmptyBridgeTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/EmptyBridgeTest.java
new file mode 100644
index 0000000..160ad59
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/EmptyBridgeTest.java
@@ -0,0 +1,63 @@
+// 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.bridgeremoval;
+
+import static com.android.tools.r8.utils.DexInspectorMatchers.isPresent;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.jasmin.JasminBuilder;
+import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.DexInspector.ClassSubject;
+import com.android.tools.r8.utils.DexInspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class EmptyBridgeTest extends TestBase {
+
+  @Test
+  public void test() throws Exception {
+    JasminBuilder jasminBuilder = new JasminBuilder();
+
+    ClassBuilder abs = jasminBuilder.addClass("Abs");
+    abs.setAccess("public abstract");
+    abs.addMethod("public bridge abstract", "emptyBridge", ImmutableList.of(), "V");
+
+    ClassBuilder cls = jasminBuilder.addClass("Main");
+    cls.addVirtualMethod("bogus", ImmutableList.of(), "V",
+        ".limit stack 3",
+        ".limit locals 2",
+        "getstatic java/lang/System/out Ljava/io/PrintStream;",
+        "ldc \"foo\"",
+        "invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
+        "return");
+    cls.addMainMethod(
+        ".limit stack 4",
+        ".limit locals 2",
+        "new " + cls.name,
+        "dup",
+        "invokespecial " + cls.name + "/<init>()V",
+        "astore_0",
+        "aload_0",
+        "invokevirtual " + cls.name + "/bogus()V",
+        "return");
+
+    String absClassName = abs.name;
+    String mainClassName = cls.name;
+    String proguardConfig =
+        "-allowaccessmodification" + System.lineSeparator()
+        + "-keep class " + mainClassName + "{ *; }" + System.lineSeparator()
+            + "-keep class " + absClassName + "{ *; }";
+    AndroidApp processedApp = compileWithR8(jasminBuilder.build(), proguardConfig);
+
+    DexInspector inspector = new DexInspector(processedApp);
+    ClassSubject classSubject = inspector.clazz(absClassName);
+    assertThat(classSubject, isPresent());
+    MethodSubject methodSubject = classSubject.method("void", "emptyBridge", ImmutableList.of());
+    assertThat(methodSubject, isPresent());
+  }
+
+}
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
index eb6e943..ba04454 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
@@ -195,7 +195,7 @@
       return addStaticMethod("main", ImmutableList.of("[Ljava/lang/String;"), "V", lines);
     }
 
-    private MethodSignature addMethod(
+    public MethodSignature addMethod(
         String access,
         String name,
         List<String> argumentTypes,