Raise an error if the given pg-map is incomplete.

Even <init> to <init> mappings should be present in the pg-map,
which have been missed at the test pg-map.

Since <clinit> may be omitted, it is handled exceptionally:
  unmapped <clinit> is not regarded as incomplete pg-map.

Bug: 71621001
Change-Id: I93f76c66a40bef11f09da95566c1a66a6d5ef6da
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
index 1a2551e..3fad0d4 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
+import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexClass;
@@ -10,6 +11,7 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItem;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
@@ -21,8 +23,8 @@
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.ThrowingConsumer;
 import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.Sets;
 import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
-import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.Set;
@@ -131,12 +133,15 @@
       DexClass clazz = appInfo.definitionFor(from);
       if (clazz == null) return;
 
-      Set<MemberNaming> appliedMemberNaming = new HashSet<>();
+      final Set<DexItem> membersNotMapped = Sets.newIdentityHashSet();
+      final Set<MemberNaming> appliedMemberNaming = Sets.newIdentityHashSet();
       clazz.forEachField(encodedField -> {
         MemberNaming memberNaming = classNaming.lookupByOriginalItem(encodedField.field);
         if (memberNaming != null) {
           appliedMemberNaming.add(memberNaming);
           applyFieldMapping(encodedField.field, memberNaming);
+        } else if (clazz.isLibraryClass()) {
+          membersNotMapped.add(encodedField.field);
         }
       });
 
@@ -145,9 +150,26 @@
         if (memberNaming != null) {
           appliedMemberNaming.add(memberNaming);
           applyMethodMapping(encodedMethod.method, memberNaming);
+        } else if (clazz.isLibraryClass()) {
+          // <clinit> mapping could be omitted.
+          if (encodedMethod.isClassInitializer()) {
+            return;
+          }
+          membersNotMapped.add(encodedMethod.method);
         }
       });
 
+      // The presence of members that are not mapped indicates incomplete mappings for libraries.
+      if (!membersNotMapped.isEmpty()) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Incomplete mappings:");
+        for (DexItem member : membersNotMapped) {
+          builder.append(System.lineSeparator()).append("  ").append(member);
+        }
+        builder.append(System.lineSeparator());
+        throw new CompilationError(builder.toString(), clazz.origin);
+      }
+
       // We need to handle a lib class that extends another lib class where some members are not
       // overridden, resulting in absence of definitions. References to those members need to be
       // redirected via lense as well.
@@ -309,11 +331,12 @@
       for (int i = 0; i < methods.length; i++) {
         DexEncodedMethod encodedMethod = methods[i];
         DexMethod appliedMethod = appliedLense.lookupMethod(encodedMethod.method, encodedMethod);
+        DexType newHolderType = substituteType(appliedMethod.holder, encodedMethod);
         DexProto newProto = substituteTypesIn(appliedMethod.proto, encodedMethod);
         DexMethod newMethod;
-        if (newProto != appliedMethod.proto) {
+        if (newHolderType != appliedMethod.holder || newProto != appliedMethod.proto) {
           newMethod = appInfo.dexItemFactory.createMethod(
-              substituteType(appliedMethod.holder, encodedMethod), newProto, appliedMethod.name);
+              substituteType(newHolderType, encodedMethod), newProto, appliedMethod.name);
           lenseBuilder.map(encodedMethod.method, newMethod);
         } else {
           newMethod = appliedMethod;
@@ -331,11 +354,12 @@
       for (int i = 0; i < fields.length; i++) {
         DexEncodedField encodedField = fields[i];
         DexField appliedField = appliedLense.lookupField(encodedField.field, null);
-        DexType newType = substituteType(appliedField.type, null);
+        DexType newHolderType = substituteType(appliedField.clazz, null);
+        DexType newFieldType = substituteType(appliedField.type, null);
         DexField newField;
-        if (newType != appliedField.type) {
+        if (newHolderType != appliedField.clazz || newFieldType != appliedField.type) {
           newField = appInfo.dexItemFactory.createField(
-              substituteType(appliedField.clazz, null), newType, appliedField.name);
+              substituteType(newHolderType, null), newFieldType, appliedField.name);
           lenseBuilder.map(encodedField.field, newField);
         } else {
           newField = appliedField;
diff --git a/src/test/examples/applymapping044/AsubB.java b/src/test/examples/applymapping044/AsubB.java
index 2c5fd0c..3df11e4 100644
--- a/src/test/examples/applymapping044/AsubB.java
+++ b/src/test/examples/applymapping044/AsubB.java
@@ -7,7 +7,11 @@
 import naming044.sub.SubB;
 
 public class AsubB extends SubB {
+  public AsubB(int f) {
+    super(f);
+  }
+
   public int boo(A a) {
-    return f(a) * 3;
+    return f(a) * f;
   }
 }
diff --git a/src/test/examples/applymapping044/Main.java b/src/test/examples/applymapping044/Main.java
index 9d5f577..a0389e8 100644
--- a/src/test/examples/applymapping044/Main.java
+++ b/src/test/examples/applymapping044/Main.java
@@ -14,7 +14,9 @@
     A a = new A();
     B b = new B();
     b.f(a);
-    AsubB subB = new AsubB();
+    AsubB aSubB = new AsubB(3);
+    aSubB.f(a);
+    SubB subB = new SubB(3);
     subB.f(a);
   }
 }
diff --git a/src/test/examples/applymapping044/test-mapping.txt b/src/test/examples/applymapping044/test-mapping.txt
index 41c2c5c..0a7d25f 100644
--- a/src/test/examples/applymapping044/test-mapping.txt
+++ b/src/test/examples/applymapping044/test-mapping.txt
@@ -1,9 +1,15 @@
 naming044.A -> naming044.x:
+    void <init>() -> <init>
     int f -> o
 naming044.B -> naming044.y:
+    void <init>() -> <init>
     int m() -> n
     int f(naming044.A) -> p
 naming044.sub.SubA -> naming044.z.x:
+    void <init>() -> <init>
     int f -> q
 naming044.sub.SubB -> naming044.z.y:
+    void <init>() -> <init>
+    void <init>(int) -> <init>
     int n() -> m
+    int f -> r
diff --git a/src/test/examples/naming044/sub/SubB.java b/src/test/examples/naming044/sub/SubB.java
index 823de8c..75d12a0 100644
--- a/src/test/examples/naming044/sub/SubB.java
+++ b/src/test/examples/naming044/sub/SubB.java
@@ -6,6 +6,12 @@
 import naming044.B;
 
 public class SubB extends B {
+  protected int f;
+
+  public SubB(int f) {
+    this.f = f;
+  }
+
   public static int n() {
     return SubA.f;
   }
diff --git a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java b/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
index 9f8061b..64c553e 100644
--- a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
@@ -30,7 +30,6 @@
 import java.util.Iterator;
 import java.util.concurrent.ExecutionException;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -62,7 +61,6 @@
   }
 
   @Test
-  @Ignore("b/71621001")
   public void test044_obfuscate_and_apply() throws Exception {
     // keep rules that allow obfuscations while keeping everything.
     Path flagForObfuscation =
@@ -121,7 +119,7 @@
     DexType a1 = f.invokedMethod().proto.parameters.values[0];
     assertNotEquals("naming044.A", a1.toString());
     assertEquals("naming044.A", mapperFromApp.deobfuscateClassName(a1.toString()));
-    assertNotEquals("f", f.invokedMethod().name.toSourceString());
+    assertNotEquals("f", f.invokedMethod().name.toString());
     // Skip AsubB#<init>
     iterator.next();
     // AsubB#f(A)
@@ -130,9 +128,20 @@
     DexType a2 = aSubB_f.proto.parameters.values[0];
     assertNotEquals("naming044.A", a2.toString());
     assertEquals("naming044.A", mapperFromApp.deobfuscateClassName(a2.toString()));
-    assertNotEquals("f", overloaded_f.invokedMethod().name.toSourceString());
+    assertNotEquals("f", aSubB_f.name.toString());
     // B#f == AsubB#f
     assertEquals(f.invokedMethod().name.toString(), aSubB_f.name.toString());
+    // sub.SubB#<init>(int)
+    InvokeInstructionSubject subBinit = iterator.next();
+    assertNotEquals("naming044.sub.SubB", subBinit.holder().toString());
+    assertEquals("naming044.sub.SubB",
+        mapperFromApp.deobfuscateClassName(subBinit.holder().toString()));
+    // sub.SubB#f(A)
+    InvokeInstructionSubject original_f = iterator.next();
+    DexMethod subB_f = original_f.invokedMethod();
+    DexType a3 = subB_f.proto.parameters.values[0];
+    assertEquals(a2, a3);
+    assertNotEquals("f", original_f.invokedMethod().name.toString());
   }
 
   @Test
@@ -153,11 +162,11 @@
     // B#m() -> y#n()
     InvokeInstructionSubject m = iterator.next();
     assertEquals("naming044.y", m.holder().toString());
-    assertEquals("n", m.invokedMethod().name.toSourceString());
+    assertEquals("n", m.invokedMethod().name.toString());
     // sub.SubB#n() -> z.y#m()
     InvokeInstructionSubject n = iterator.next();
     assertEquals("naming044.z.y", n.holder().toString());
-    assertEquals("m", n.invokedMethod().name.toSourceString());
+    assertEquals("m", n.invokedMethod().name.toString());
     // Skip A#<init>
     iterator.next();
     // Skip B#<init>
@@ -166,7 +175,7 @@
     InvokeInstructionSubject f = iterator.next();
     DexType a1 = f.invokedMethod().proto.parameters.values[0];
     assertEquals("naming044.x", a1.toString());
-    assertEquals("p", f.invokedMethod().name.toSourceString());
+    assertEquals("p", f.invokedMethod().name.toString());
     // Skip AsubB#<init>
     iterator.next();
     // AsubB#f(A) -> AsubB#p(x)
@@ -174,9 +183,18 @@
     DexMethod aSubB_f = overloaded_f.invokedMethod();
     DexType a2 = aSubB_f.proto.parameters.values[0];
     assertEquals("naming044.x", a2.toString());
-    assertEquals("p", aSubB_f.name.toSourceString());
+    assertEquals("p", aSubB_f.name.toString());
     // B#f == AsubB#f
     assertEquals(f.invokedMethod().name.toString(), aSubB_f.name.toString());
+    // sub.SubB#<init>(int) -> z.y<init>(int)
+    InvokeInstructionSubject subBinit = iterator.next();
+    assertEquals("naming044.z.y", subBinit.holder().toString());
+    // sub.SubB#f(A) -> SubB#p(x)
+    InvokeInstructionSubject original_f = iterator.next();
+    DexMethod subB_f = original_f.invokedMethod();
+    DexType a3 = subB_f.proto.parameters.values[0];
+    assertEquals(a2, a3);
+    assertEquals("p", original_f.invokedMethod().name.toString());
   }
 
   @Test