Generalize isSimpleRenaming to check for renamed types in members

Bug: 180092122
Change-Id: Iecb3fdfe2705b92701d23451bb346c4be3c1fda6
diff --git a/src/main/java/com/android/tools/r8/graph/DexReference.java b/src/main/java/com/android/tools/r8/graph/DexReference.java
index 27264bb..e813d7c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexReference.java
+++ b/src/main/java/com/android/tools/r8/graph/DexReference.java
@@ -4,7 +4,9 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.errors.Unreachable;
 import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
@@ -27,6 +29,22 @@
       BiConsumer<DexMethod, T> methodConsumer,
       T arg);
 
+  public static <R extends DexReference, T> T applyPair(
+      R one,
+      R other,
+      BiFunction<DexType, DexType, T> classConsumer,
+      BiFunction<DexField, DexField, T> fieldConsumer,
+      BiFunction<DexMethod, DexMethod, T> methodConsumer) {
+    if (one.isDexType()) {
+      return classConsumer.apply(one.asDexType(), other.asDexType());
+    } else if (one.isDexField()) {
+      return fieldConsumer.apply(one.asDexField(), other.asDexField());
+    } else if (one.isDexMethod()) {
+      return methodConsumer.apply(one.asDexMethod(), other.asDexMethod());
+    }
+    throw new Unreachable();
+  }
+
   public abstract void collectIndexedItems(IndexedItemCollection indexedItems);
 
   public abstract int compareTo(DexReference other);
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index a296543..43e733c 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -355,10 +355,12 @@
     return newMethod.lookupOnProgramClass(holder);
   }
 
-  // Predicate indicating if a rewritten type is a simple renaming, meaning the move from type to
-  // rewritten is just a renaming of the type to another. In other words, the content of the
-  // definition, including the definition of all of its members is the same modulo the renaming.
-  public boolean isSimpleRenaming(DexType from, DexType to) {
+  // Predicate indicating if a rewritten reference is a simple renaming, meaning the move from one
+  // reference to another is simply either just a renaming or/also renaming of the references. In
+  // other words, the content of the definition, including the definition of all of its members is
+  // the same modulo the renaming.
+  public <T extends DexReference> boolean isSimpleRenaming(T from, T to) {
+    assert from != to;
     return false;
   }
 
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
index 0fe63b8..63b8d06 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
@@ -6,10 +6,13 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMember;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
 import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
@@ -42,8 +45,36 @@
   }
 
   @Override
-  public boolean isSimpleRenaming(DexType from, DexType to) {
-    return originalTypes.get(to) == from || super.isSimpleRenaming(from, to);
+  public <T extends DexReference> boolean isSimpleRenaming(T from, T to) {
+    if (from == to) {
+      assert false : "The from and to references should not be equal";
+      return false;
+    }
+    if (super.isSimpleRenaming(from, to)) {
+      // Repackaging only move classes and therefore if a previous lens has a simple renaming it
+      // will be maintained here.
+      return true;
+    }
+    return DexReference.applyPair(
+        from,
+        to,
+        this::isSimpleTypeRenamingOrEqual,
+        this::isSimpleTypeRenamingOrEqual,
+        this::isSimpleTypeRenamingOrEqual);
+  }
+
+  private boolean isSimpleTypeRenamingOrEqual(DexType from, DexType to) {
+    return from == to || originalTypes.get(to) == from;
+  }
+
+  private boolean isSimpleTypeRenamingOrEqual(DexMember<?, ?> from, DexMember<?, ?> to) {
+    if (!isSimpleTypeRenamingOrEqual(from.getHolderType(), to.getHolderType())) {
+      return false;
+    }
+    return IterableUtils.testPairs(
+        this::isSimpleTypeRenamingOrEqual,
+        from.getReferencedBaseTypes(dexItemFactory),
+        to.getReferencedBaseTypes(dexItemFactory));
   }
 
   public static class Builder {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
index fd63ea2..dfc240b 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
@@ -57,7 +57,7 @@
     DexMethod rewritten = lens.lookupMethod(method);
     // If the reference has been non-trivially rewritten the compiler has changed it and it can no
     // longer be considered a synthetic. The context may or may not have changed.
-    if (method != rewritten && !lens.isSimpleRenaming(method.holder, rewritten.holder)) {
+    if (method != rewritten && !lens.isSimpleRenaming(method, rewritten)) {
       // If the referenced item is rewritten, it should be moved to another holder as the
       // synthetic holder is no longer part of the synthetic collection.
       assert method.holder != rewritten.holder : "The synthetic method reference should have moved";
diff --git a/src/main/java/com/android/tools/r8/utils/IterableUtils.java b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
index 2b0267d..ce8396f 100644
--- a/src/main/java/com/android/tools/r8/utils/IterableUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
@@ -8,8 +8,10 @@
 import com.google.common.collect.Iterators;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
@@ -130,4 +132,23 @@
       return iterable;
     }
   }
+
+  /**
+   * Utility method for testing the the elements in one and other pair-wise. Returns false if the
+   * lengths differ.
+   */
+  public static <T> boolean testPairs(
+      BiPredicate<T, T> predicate, Iterable<T> one, Iterable<T> other) {
+    Iterator<T> iterator = other.iterator();
+    for (T first : one) {
+      if (!iterator.hasNext()) {
+        return false;
+      }
+      T second = iterator.next();
+      if (!predicate.test(first, second)) {
+        return false;
+      }
+    }
+    return !iterator.hasNext();
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageParameterSyntheticOutlineTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageParameterSyntheticOutlineTest.java
index 0636a50..9e2f6c2 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageParameterSyntheticOutlineTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageParameterSyntheticOutlineTest.java
@@ -4,11 +4,8 @@
 
 package com.android.tools.r8.repackage;
 
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
-import static org.hamcrest.CoreMatchers.containsString;
 
-import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -49,7 +46,7 @@
         .assertSuccessWithOutputLines(EXPECTED);
   }
 
-  @Test(expected = CompilationFailedException.class)
+  @Test
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
         .addProgramClasses(Param.class, Return.class)
@@ -67,13 +64,8 @@
             })
         .apply(this::configureRepackaging)
         .addKeepPackageNamesRule("bar**")
-        .compileWithExpectedDiagnostics(
-            diagnostics -> {
-              // TODO(b/180092122): This should not fail.
-              diagnostics.assertErrorsMatch(
-                  diagnosticMessage(
-                      containsString("The synthetic method reference should have moved")));
-            });
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED);
   }
 
   private byte[] rewrittenPackageForClassWithCodeToBeOutlined() throws Exception {