Store scoped mapping info on the side.

Bug: 172014416
Change-Id: Ia90fc8a032202497d16918f0e21f0385375ea035
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index af62c60..14c2179 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -15,14 +15,16 @@
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
 import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ScopeReference;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.utils.BiMapContainer;
 import com.android.tools.r8.utils.ChainableStringConsumer;
-import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.io.CharSource;
 import java.io.BufferedReader;
@@ -31,7 +33,6 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -48,7 +49,7 @@
 
   public static class Builder extends ProguardMap.Builder {
     private final Map<String, ClassNamingForNameMapper.Builder> mapping = new HashMap<>();
-    private final Map<String, List<ScopedMappingInformation>> scopedMappingInfo = new HashMap<>();
+    private final Map<ScopeReference, List<MappingInformation>> scopedMappingInfo = new HashMap<>();
 
     private Builder() {
 
@@ -72,26 +73,28 @@
 
     @Override
     public ClassNameMapper build() {
-      return new ClassNameMapper(buildClassNameMappings());
+      return new ClassNameMapper(buildClassNameMappings(), buildScopedMappingInfo());
+    }
+
+    private ImmutableMap<ScopeReference, ImmutableList<MappingInformation>>
+        buildScopedMappingInfo() {
+      ImmutableMap.Builder<ScopeReference, ImmutableList<MappingInformation>> builder =
+          ImmutableMap.builder();
+      scopedMappingInfo.forEach((ref, infos) -> builder.put(ref, ImmutableList.copyOf(infos)));
+      return builder.build();
     }
 
     private ImmutableMap<String, ClassNamingForNameMapper> buildClassNameMappings() {
       // Ensure that all scoped references have at least the identity in the final mapping.
-      for (String descriptor : scopedMappingInfo.keySet()) {
-        String typename = DescriptorUtils.descriptorToJavaType(descriptor);
-        mapping.computeIfAbsent(typename, t -> ClassNamingForNameMapper.builder(t, t));
+      for (ScopeReference reference : scopedMappingInfo.keySet()) {
+        mapping.computeIfAbsent(
+            reference.getHolderReference().getTypeName(),
+            t -> ClassNamingForNameMapper.builder(t, t));
       }
-      // Build the final mapping while amending any entries with the scoped info.
       ImmutableMap.Builder<String, ClassNamingForNameMapper> builder = ImmutableMap.builder();
       builder.orderEntriesByValue(Comparator.comparing(x -> x.originalName));
       mapping.forEach(
-          (renamedName, valueBuilder) -> {
-            String descriptor = DescriptorUtils.javaTypeToDescriptor(renamedName);
-            scopedMappingInfo
-                .getOrDefault(descriptor, Collections.emptyList())
-                .forEach(valueBuilder::addMappingInformation);
-            builder.put(renamedName, valueBuilder.build());
-          });
+          (renamedName, valueBuilder) -> builder.put(renamedName, valueBuilder.build()));
       return builder.build();
     }
   }
@@ -152,17 +155,26 @@
   }
 
   private final ImmutableMap<String, ClassNamingForNameMapper> classNameMappings;
+  private final ImmutableMap<ScopeReference, ImmutableList<MappingInformation>>
+      additionalMappingInfo;
   private BiMapContainer<String, String> nameMapping;
   private final Map<Signature, Signature> signatureMap = new HashMap<>();
 
-  private ClassNameMapper(ImmutableMap<String, ClassNamingForNameMapper> classNameMappings) {
+  private ClassNameMapper(
+      ImmutableMap<String, ClassNamingForNameMapper> classNameMappings,
+      ImmutableMap<ScopeReference, ImmutableList<MappingInformation>> additionalMappingInfo) {
     this.classNameMappings = classNameMappings;
+    this.additionalMappingInfo = additionalMappingInfo;
   }
 
   public Map<String, ClassNamingForNameMapper> getClassNameMappings() {
     return classNameMappings;
   }
 
+  public List<MappingInformation> getAdditionalMappingInfo(ScopeReference reference) {
+    return additionalMappingInfo.getOrDefault(reference, ImmutableList.of());
+  }
+
   private Signature canonicalizeSignature(Signature signature) {
     Signature result = signatureMap.get(signature);
     if (result != null) {
@@ -232,7 +244,7 @@
     ImmutableMap.Builder<String, ClassNamingForNameMapper> builder = ImmutableMap.builder();
     builder.orderEntriesByValue(Comparator.comparing(x -> x.originalName));
     classNameMappings.forEach(builder::put);
-    return new ClassNameMapper(builder.build());
+    return new ClassNameMapper(builder.build(), additionalMappingInfo);
   }
 
   public boolean verifyIsSorted() {
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java
index deb0440..4385f5a 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java
@@ -22,15 +22,28 @@
   // to map to java.lang.String with the post-minification names.
   public abstract static class ScopeReference {
 
+    public static ScopeReference fromClassReference(ClassReference reference) {
+      return new ClassScopeReference(reference);
+    }
+
+    // Method for reading in the serialized reference format.
     public static ScopeReference fromReferenceString(String referenceString) {
       if (DescriptorUtils.isClassDescriptor(referenceString)) {
-        return new ClassScopeReference(Reference.classFromDescriptor(referenceString));
+        return fromClassReference(Reference.classFromDescriptor(referenceString));
       }
       throw new Unimplemented("No support for reference: " + referenceString);
     }
 
     public abstract String toReferenceString();
 
+    public abstract ClassReference getHolderReference();
+
+    @Override
+    public abstract boolean equals(Object other);
+
+    @Override
+    public abstract int hashCode();
+
     @Override
     public String toString() {
       return toReferenceString();
@@ -38,9 +51,10 @@
   }
 
   public static class ClassScopeReference extends ScopeReference {
-    final ClassReference reference;
+    private final ClassReference reference;
 
     public ClassScopeReference(ClassReference reference) {
+      assert reference != null;
       this.reference = reference;
     }
 
@@ -48,6 +62,22 @@
     public String toReferenceString() {
       return reference.getDescriptor();
     }
+
+    @Override
+    public ClassReference getHolderReference() {
+      return reference;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+      return other instanceof ClassScopeReference
+          && reference.equals(((ClassScopeReference) other).reference);
+    }
+
+    @Override
+    public int hashCode() {
+      return reference.hashCode();
+    }
   }
 
   public abstract static class Builder<B extends Builder<B>> {
@@ -109,9 +139,9 @@
     return this;
   }
 
-  public void forEach(BiConsumer<String, ScopedMappingInformation> fn) {
+  public void forEach(BiConsumer<ScopeReference, MappingInformation> fn) {
     for (ScopeReference reference : scopeReferences) {
-      fn.accept(reference.toReferenceString(), this);
+      fn.accept(reference, this);
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index c830cf6..b782ae2 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -28,6 +28,8 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.ClassNamingForNameMapper;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ScopeReference;
 import com.android.tools.r8.naming.signature.GenericSignatureAction;
 import com.android.tools.r8.naming.signature.GenericSignatureParser;
 import com.android.tools.r8.origin.Origin;
@@ -248,6 +250,49 @@
     return clazz(Reference.classFromTypeName(name));
   }
 
+  // Simple wrapper to more easily change the implementation for retracing subjects.
+  // This should in time be replaced by use of the Retrace API.
+  public static class MappingWrapper {
+
+    private static final MappingWrapper EMPTY =
+        new MappingWrapper(null, null) {
+          @Override
+          public Collection<MappingInformation> getAdditionalMappings() {
+            return Collections.emptyList();
+          }
+
+          @Override
+          public ClassNamingForNameMapper getNaming() {
+            return null;
+          }
+        };
+
+    static MappingWrapper create(ClassNameMapper mapper, ClassNamingForNameMapper naming) {
+      if (mapper == null || naming == null) {
+        return EMPTY;
+      }
+      return new MappingWrapper(mapper, naming);
+    }
+
+    private final ClassNameMapper mapper;
+    private final ClassNamingForNameMapper naming;
+
+    private MappingWrapper(ClassNameMapper mapper, ClassNamingForNameMapper naming) {
+      this.mapper = mapper;
+      this.naming = naming;
+    }
+
+    public Collection<MappingInformation> getAdditionalMappings() {
+      return mapper.getAdditionalMappingInfo(
+          ScopeReference.fromClassReference(Reference.classFromTypeName(naming.renamedName)));
+    }
+
+    public ClassNamingForNameMapper getNaming() {
+      assert naming != null;
+      return naming;
+    }
+  }
+
   public ClassSubject clazz(ClassReference reference) {
     String descriptor = reference.getDescriptor();
     String name = DescriptorUtils.descriptorToJavaType(descriptor);
@@ -269,7 +314,7 @@
     if (clazz == null) {
       return new AbsentClassSubject(this, reference);
     }
-    return new FoundClassSubject(this, clazz, naming, reference);
+    return new FoundClassSubject(this, clazz, MappingWrapper.create(mapping, naming), reference);
   }
 
   public ClassSubject companionClassFor(Class<?> clazz) {
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 40deb3d..c69c4a0 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
@@ -40,6 +40,7 @@
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.ZipUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector.MappingWrapper;
 import com.google.common.collect.Sets;
 import java.io.File;
 import java.nio.file.Paths;
@@ -54,16 +55,16 @@
 public class FoundClassSubject extends ClassSubject {
 
   private final DexClass dexClass;
-  final ClassNamingForNameMapper naming;
+  private final MappingWrapper mapping;
 
   FoundClassSubject(
       CodeInspector codeInspector,
       DexClass dexClass,
-      ClassNamingForNameMapper naming,
+      MappingWrapper mapping,
       ClassReference reference) {
     super(codeInspector, reference);
     this.dexClass = dexClass;
-    this.naming = naming;
+    this.mapping = mapping;
   }
 
   @Override
@@ -100,10 +101,10 @@
     DexProto proto =
         codeInspector.dexItemFactory.createProto(
             codeInspector.toDexType(codeInspector.getObfuscatedTypeName(returnType)), parameterTypes);
-    if (naming != null) {
+    if (getNaming() != null) {
       Signature signature =
           new MethodSignature(name, returnType, parameters.toArray(StringUtils.EMPTY_ARRAY));
-      MemberNaming methodNaming = naming.lookupByOriginalSignature(signature);
+      MemberNaming methodNaming = getNaming().lookupByOriginalSignature(signature);
       if (methodNaming != null) {
         name = methodNaming.getRenamedName();
       }
@@ -191,8 +192,8 @@
   public FieldSubject field(String type, String name) {
     String obfuscatedType = codeInspector.getObfuscatedTypeName(type);
     MemberNaming fieldNaming = null;
-    if (naming != null) {
-      fieldNaming = naming.lookupByOriginalSignature(new FieldSignature(name, type));
+    if (getNaming() != null) {
+      fieldNaming = getNaming().lookupByOriginalSignature(new FieldSignature(name, type));
     }
     String obfuscatedName = fieldNaming == null ? name : fieldNaming.getRenamedName();
 
@@ -357,8 +358,8 @@
 
   @Override
   public String getOriginalName() {
-    if (naming != null) {
-      return naming.originalName;
+    if (getNaming() != null) {
+      return getNaming().originalName;
     } else {
       return getFinalName();
     }
@@ -366,8 +367,8 @@
 
   @Override
   public String getOriginalDescriptor() {
-    if (naming != null) {
-      return DescriptorUtils.javaTypeToDescriptor(naming.originalName);
+    if (getNaming() != null) {
+      return DescriptorUtils.javaTypeToDescriptor(getNaming().originalName);
     } else {
       return getFinalDescriptor();
     }
@@ -409,15 +410,12 @@
 
   @Override
   public boolean isRenamed() {
-    return naming != null && !getFinalDescriptor().equals(getOriginalDescriptor());
+    return getNaming() != null && !getFinalDescriptor().equals(getOriginalDescriptor());
   }
 
   @Override
   public boolean isCompilerSynthesized() {
-    if (naming == null) {
-      return false;
-    }
-    for (MappingInformation info : naming.getAdditionalMappings()) {
+    for (MappingInformation info : mapping.getAdditionalMappings()) {
       if (info.isCompilerSynthesizedMappingInformation()) {
         return true;
       }
@@ -467,7 +465,7 @@
   public int hashCode() {
     int result = codeInspector.hashCode();
     result = 31 * result + dexClass.hashCode();
-    result = 31 * result + (naming != null ? naming.hashCode() : 0);
+    result = 31 * result + (getNaming() != null ? getNaming().hashCode() : 0);
     return result;
   }
 
@@ -479,7 +477,7 @@
     FoundClassSubject otherSubject = (FoundClassSubject) other;
     return codeInspector == otherSubject.codeInspector
         && dexClass == otherSubject.dexClass
-        && naming == otherSubject.naming;
+        && getNaming() == otherSubject.getNaming();
   }
 
   @Override
@@ -538,7 +536,7 @@
 
   @Override
   public ClassNamingForNameMapper getNaming() {
-    return naming;
+    return mapping.getNaming();
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
index 023f412..26466c1 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
@@ -39,7 +39,8 @@
 
   @Override
   public boolean isRenamed() {
-    return clazz.naming != null && !getFinalSignature().name.equals(getOriginalSignature().name);
+    return clazz.getNaming() != null
+        && !getFinalSignature().name.equals(getOriginalSignature().name);
   }
 
   public TypeSubject type() {
@@ -49,7 +50,7 @@
   @Override
   public FieldSignature getOriginalSignature() {
     FieldSignature signature = getFinalSignature();
-    if (clazz.naming == null) {
+    if (clazz.getNaming() == null) {
       return signature;
     }
 
@@ -66,7 +67,7 @@
     String fieldType = originalType != null ? originalType : obfuscatedType;
     FieldSignature lookupSignature = new FieldSignature(signature.name, fieldType);
 
-    MemberNaming memberNaming = clazz.naming.lookup(lookupSignature);
+    MemberNaming memberNaming = clazz.getNaming().lookup(lookupSignature);
     return memberNaming != null
         ? (FieldSignature) memberNaming.getOriginalSignature()
         : lookupSignature;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index f215cca..268c51a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -78,7 +78,8 @@
 
   @Override
   public boolean isRenamed() {
-    return clazz.naming != null && !getFinalSignature().name.equals(getOriginalSignature().name);
+    return clazz.getNaming() != null
+        && !getFinalSignature().name.equals(getOriginalSignature().name);
   }
 
   @Override
@@ -129,7 +130,7 @@
   @Override
   public MethodSignature getOriginalSignature() {
     MethodSignature signature = getFinalSignature();
-    if (clazz.naming == null) {
+    if (clazz.getNaming() == null) {
       return signature;
     }
 
@@ -149,7 +150,7 @@
     MethodSignature lookupSignature =
         new MethodSignature(signature.name, returnType, originalParameters);
 
-    MemberNaming memberNaming = clazz.naming.lookup(lookupSignature);
+    MemberNaming memberNaming = clazz.getNaming().lookup(lookupSignature);
     return memberNaming != null ? (MethodSignature) memberNaming.getOriginalSignature() : signature;
   }