Fix inadequate keep rule generating in trace references

Bug: b/397904338
Change-Id: I3d613d57f8de37a3c5670b6d843e1edc402591e7
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Formatter.java b/src/main/java/com/android/tools/r8/tracereferences/Formatter.java
index 2f19681..e3978f3 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Formatter.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Formatter.java
@@ -10,10 +10,14 @@
 import com.android.tools.r8.tracereferences.TraceReferencesConsumer.TracedClass;
 import com.android.tools.r8.tracereferences.TraceReferencesConsumer.TracedField;
 import com.android.tools.r8.tracereferences.TraceReferencesConsumer.TracedMethod;
+import com.android.tools.r8.tracereferences.TraceReferencesConsumer.TracedReference;
 import com.android.tools.r8.tracereferences.internal.TraceReferencesResult;
+import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.MapUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.StringUtils.BraceType;
+import com.google.common.collect.Streams;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -89,13 +93,14 @@
       Set<PackageReference> keepPackageNames,
       Map<ClassReference, Set<TracedField>> fields,
       Map<ClassReference, Set<TracedMethod>> methods) {
-    List<TracedClass> sortedTypes = new ArrayList<>(types);
-    sortedTypes.sort(Comparator.comparing(tracedClass -> tracedClass.getReference().getTypeName()));
+    List<TracedClass> sortedTypes =
+        ListUtils.sort(
+            types, Comparator.comparing(tracedClass -> tracedClass.getReference().getDescriptor()));
     for (TracedClass type : sortedTypes) {
       Set<TracedMethod> methodsForClass =
-          methods.getOrDefault(type.getReference(), Collections.emptySet());
+          MapUtils.removeOrDefault(methods, type.getReference(), Collections.emptySet());
       Set<TracedField> fieldsForClass =
-          fields.getOrDefault(type.getReference(), Collections.emptySet());
+          MapUtils.removeOrDefault(fields, type.getReference(), Collections.emptySet());
       if (type.isMissingDefinition()) {
         continue;
       }
@@ -123,6 +128,10 @@
       }
       printTypeFooter();
     }
+    assert Streams.stream(IterableUtils.flatten(fields.values()))
+        .allMatch(TracedReference::isMissingDefinition);
+    assert Streams.stream(IterableUtils.flatten(methods.values()))
+        .allMatch(TracedReference::isMissingDefinition);
     List<String> packageNamesToKeep =
         keepPackageNames.stream()
             .map(PackageReference::getPackageName)
diff --git a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
index 22ec0d0..6bcaf98 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
@@ -123,6 +123,12 @@
     consumer.acceptMethod(tracedMethod, diagnostics);
   }
 
+  protected void notifyPresentMethod(
+      DexClassAndMethod method, DefinitionContext referencedFrom, DexMethod reference) {
+    TracedMethodImpl tracedMethod = new TracedMethodImpl(method, referencedFrom, reference);
+    consumer.acceptMethod(tracedMethod, diagnostics);
+  }
+
   protected void notifyPackageOf(Definition definition) {
     consumer.acceptPackage(
         Reference.packageFromString(definition.getContextType().getPackageName()), diagnostics);
@@ -212,19 +218,6 @@
     }
   }
 
-  private void addSuperMethodFromTarget(
-      DexClassAndMethod method, ProgramMethod context, DefinitionContext referencedFrom) {
-    assert !method.isProgramMethod();
-    assert isTargetType(method.getHolderType());
-    // There should be no need to register the types referenced from the method signature:
-    // - The return type and the parameter types are registered when visiting the source method
-    //   that overrides this target method,
-    // - The holder type is registered from visiting the extends/implements clause of the sub
-    //   class.
-    notifyPresentMethod(method, referencedFrom);
-    ensurePackageAccessToMember(method, context.getHolder());
-  }
-
   private <R, T extends TracedReference<R, ?>> void collectMissing(
       T tracedReference, Set<R> missingCollection) {
     if (tracedReference.isMissingDefinition()) {
@@ -291,7 +284,23 @@
           if (resolvedMethod != null
               && !resolvedMethod.isProgramMethod()
               && isTargetType(resolvedMethod.getHolderType())) {
-            addSuperMethodFromTarget(resolvedMethod, method, referencedFrom);
+            // There should be no need to register the types referenced from the method signature:
+            // - The return type and the parameter types are registered when visiting the source
+            //   method that overrides this target method,
+            // - The holder type is registered from visiting the extends/implements clause of the
+            //   sub class.
+            if (resolvedMethod.getHolderType().isIdenticalTo(superType)) {
+              notifyPresentMethod(resolvedMethod, referencedFrom);
+            } else if (isTargetType(superType)) {
+              notifyPresentMethod(
+                  resolvedMethod,
+                  referencedFrom,
+                  resolvedMethod.getReference().withHolder(superType, factory));
+            } else {
+              notifyPresentMethod(resolvedMethod, referencedFrom);
+              addClass(resolvedMethod.getHolder(), referencedFrom);
+            }
+            ensurePackageAccessToMember(resolvedMethod, method.getHolder());
           }
         });
   }
diff --git a/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java b/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
index 2e315df..22f7671 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
@@ -26,6 +26,14 @@
   }
 
   public TracedMethodImpl(
+      DexClassAndMethod method, DefinitionContext referencedFrom, DexMethod reference) {
+    this(
+        reference.asMethodReference(),
+        referencedFrom,
+        new MethodAccessFlagsImpl(method.getAccessFlags()));
+  }
+
+  public TracedMethodImpl(
       MethodReference methodReference,
       DefinitionContext referencedFrom,
       MethodAccessFlags accessFlags) {
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesIndirectOverrideTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesIndirectOverrideTest.java
index cc255ed..771e4e3 100644
--- a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesIndirectOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesIndirectOverrideTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.tracereferences;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestBase;
@@ -57,8 +56,7 @@
                     .setOutputConsumer(testingKeepRuleConsumer)
                     .build())
             .build());
-    // TODO(b/397904338): shouldBeKept() should be kept.
-    assertThat(testingKeepRuleConsumer.get(), not(containsString("shouldBeKept")));
+    assertThat(testingKeepRuleConsumer.get(), containsString("shouldBeKept"));
   }
 
   static class A {