Nest Access: Private access inside a class

- private accesses inside a class were rewritten
to a call to the bridge, if the bridge was needed for other
reasons. This was correct but was not necessary.
- added tests for it (Turns out d8 was sometimes generating
extra bridges)

Bug:132147078
Change-Id: I3ac6b7cebd81eaa1424d591d3190b95280ba31e4
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
index d4e25df..4eb29a1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
@@ -94,7 +94,7 @@
       DexMethod method,
       Map<DexField, DexMethod> fieldToMethodMap) {
     DexMethod newTarget = fieldToMethodMap.get(fieldInstruction.getField());
-    if (newTarget != null && method != newTarget) {
+    if (newTarget != null && method.holder != newTarget.holder) {
       instructions.replaceCurrentInstruction(
           new InvokeStatic(newTarget, fieldInstruction.outValue(), fieldInstruction.inValues()));
     }
@@ -126,7 +126,7 @@
                 new InvokeStatic(newTarget, invokeMethod.outValue(), invokeMethod.arguments()));
           } else {
             newTarget = initializerMap.get(methodCalled);
-            if (newTarget != null && encodedMethod.method != newTarget) {
+            if (newTarget != null && encodedMethod.method.holder != newTarget.holder) {
               // insert extra null value and replace call.
               instructions.previous();
               Value extraNullValue =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java b/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
index a324d61b..0411ea4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
@@ -164,10 +164,9 @@
       // All generated initializer bridges are direct.
       newType = Invoke.Type.DIRECT;
     }
-    if (newMethod == context) {
-      // Bridges should not rewrite themselves.
-      // TODO(b/130529338): Best would be that if we are in Class A and targeting class
-      // A private method, we do not rewrite it.
+    if (context != null && newMethod.holder == context.holder) {
+      // Without context we conservatively rewrite the method.
+      // Private calls inside a class do not need to be rewritten.
       return previous;
     }
     return new GraphLenseLookupResult(newMethod, newType);
diff --git a/src/test/examplesJava11/nestHostExample/BasicNestHostWithInnerClassFields.java b/src/test/examplesJava11/nestHostExample/BasicNestHostWithInnerClassFields.java
index a16f6a6..f23ef4b 100644
--- a/src/test/examplesJava11/nestHostExample/BasicNestHostWithInnerClassFields.java
+++ b/src/test/examplesJava11/nestHostExample/BasicNestHostWithInnerClassFields.java
@@ -6,6 +6,7 @@
 
 public class BasicNestHostWithInnerClassFields {
 
+  private String fieldWithoutBridge = "noBridge";
   private String field = "field";
   private static String staticField = "staticField";
 
@@ -13,7 +14,7 @@
   public String accessNested(BasicNestedClass o) {
     o.field = "RW" + o.field;
     o.staticField = "RW" + o.field;
-    return o.field + o.staticField + BasicNestedClass.staticField;
+    return o.field + o.staticField + BasicNestedClass.staticField + fieldWithoutBridge;
   }
 
   public static class BasicNestedClass {
diff --git a/src/test/examplesJava11/nestHostExample/BasicNestHostWithInnerClassMethods.java b/src/test/examplesJava11/nestHostExample/BasicNestHostWithInnerClassMethods.java
index 1313ef5..1b6e1f1 100644
--- a/src/test/examplesJava11/nestHostExample/BasicNestHostWithInnerClassMethods.java
+++ b/src/test/examplesJava11/nestHostExample/BasicNestHostWithInnerClassMethods.java
@@ -6,6 +6,10 @@
 
 public class BasicNestHostWithInnerClassMethods {
 
+  private String methodWithoutBridge() {
+    return "noBridge";
+  }
+
   private String method() {
     return "hostMethod";
   }
@@ -16,7 +20,7 @@
 
   @SuppressWarnings("static-access") // we want to test that too.
   public String accessNested(BasicNestedClass o) {
-    return o.method() + o.staticMethod() + BasicNestedClass.staticMethod();
+    return o.method() + o.staticMethod() + BasicNestedClass.staticMethod() + methodWithoutBridge();
   }
 
   public static class BasicNestedClass {
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAccessControlTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAccessControlTest.java
index f3e1851..16312c7 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAccessControlTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAccessControlTest.java
@@ -27,6 +27,7 @@
 import com.android.tools.r8.graph.DexClass;
 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.FoundClassSubject;
 import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
@@ -206,6 +207,32 @@
     testR8("all");
   }
 
+  private void assertOnlyRequiredBridges(CodeInspector inspector) {
+    // The following 2 classes have an extra private member which does not require a bridge.
+
+    // Two bridges for method and staticMethod.
+    int methodNumBridges = parameters.isCfRuntime() ? 0 : 2;
+    ClassSubject methodMainClass = inspector.clazz(getMainClass("methods"));
+    assertEquals(
+        methodNumBridges, methodMainClass.allMethods(FoundMethodSubject::isSynthetic).size());
+
+    // Four bridges for field and staticField, both get & set.
+    int fieldNumBridges = parameters.isCfRuntime() ? 0 : 4;
+    ClassSubject fieldMainClass = inspector.clazz(getMainClass("fields"));
+    assertEquals(
+        fieldNumBridges, fieldMainClass.allMethods(FoundMethodSubject::isSynthetic).size());
+  }
+
+  @Test
+  public void testOnlyRequiredBridges() throws Exception {
+    if (parameters.isDexRuntime()) {
+      d8CompilationResult.apply(parameters.getApiLevel()).inspect(this::assertOnlyRequiredBridges);
+    }
+    r8CompilationResult
+        .apply(parameters.getBackend(), parameters.getApiLevel())
+        .inspect(this::assertOnlyRequiredBridges);
+  }
+
   private static void checkNestMateAttributes(CodeInspector inspector) {
     // Interface method desugaring may add extra classes
     assertTrue(NUMBER_OF_TEST_CLASSES <= inspector.allClasses().size());