[GlobalSynthetics] Add record tag to output

Bug: b/280016114
Change-Id: I27703f41170f5215dce48651bb305ea163262245
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
index 12df474..827931b 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
@@ -30,8 +30,13 @@
 import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.MethodCollection.MethodCollectionFactory;
 import com.android.tools.r8.graph.NestHostClassAttribute;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.ThrowExceptionCode;
+import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.desugar.TypeRewriter;
+import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.naming.RecordRewritingNamingLens;
 import com.android.tools.r8.origin.CommandLineOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.MainDexInfo;
@@ -47,7 +52,9 @@
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -154,11 +161,22 @@
     Set<DexProgramClass> synthesizingContext =
         ImmutableSet.of(createSynthesizingContext(appView.dexItemFactory()));
 
-    // TODO(b/280016114): Create record tag
+    List<ProgramMethod> methodsToProcess = new ArrayList<>();
+    RecordDesugaring.ensureRecordClassHelper(
+        appView,
+        synthesizingContext,
+        recordTagClass -> recordTagClass.programMethods().forEach(methodsToProcess::add));
+    NamingLens namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView);
+
     // TODO(b/280016114): Create Var Handle
     // TODO(b/280016114): Create MethodHandlesLookup
+
     createAllApiStubs(appView, synthesizingContext, executorService);
 
+    appView.setNamingLens(namingLens);
+    IRConverter converter = new IRConverter(appView);
+    converter.processSimpleSynthesizeMethods(methodsToProcess, executorService);
+
     appView
         .withoutClassHierarchy()
         .setAppInfo(
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index a5417c6..7b531fb 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -349,14 +349,13 @@
     return onWaveDoneActions != null;
   }
 
-  protected void processSimpleSynthesizeMethods(
-      List<ProgramMethod> serviceLoadMethods, ExecutorService executorService)
-      throws ExecutionException {
+  public void processSimpleSynthesizeMethods(
+      List<ProgramMethod> methods, ExecutorService executorService) throws ExecutionException {
     ThreadUtils.processItems(
-        serviceLoadMethods, this::processAndFinalizeSimpleSynthesiedMethod, executorService);
+        methods, this::processAndFinalizeSimpleSynthesizedMethod, executorService);
   }
 
-  private void processAndFinalizeSimpleSynthesiedMethod(ProgramMethod method) {
+  private void processAndFinalizeSimpleSynthesizedMethod(ProgramMethod method) {
     IRCode code = method.buildIR(appView);
     assert code != null;
     codeRewriter.rewriteMoveResult(code);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
index 4e982d8..5cd5230 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
@@ -442,16 +442,23 @@
       Collection<? extends ProgramDefinition> contexts) {
     DexItemFactory factory = appView.dexItemFactory();
     checkRecordTagNotPresent(factory);
+    return ensureRecordClassHelper(appView, contexts, eventConsumer);
+  }
+
+  public static DexProgramClass ensureRecordClassHelper(
+      AppView<?> appView,
+      Collection<? extends ProgramDefinition> contexts,
+      RecordDesugaringEventConsumer eventConsumer) {
     return appView
         .getSyntheticItems()
         .ensureGlobalClass(
             () -> new MissingGlobalSyntheticsConsumerDiagnostic("Record desugaring"),
             kinds -> kinds.RECORD_TAG,
-            factory.recordType,
+            appView.dexItemFactory().recordType,
             contexts,
             appView,
             builder -> {
-              DexEncodedMethod init = synthesizeRecordInitMethod();
+              DexEncodedMethod init = synthesizeRecordInitMethod(appView);
               builder.setAbstract().setDirectMethods(ImmutableList.of(init));
             },
             eventConsumer::acceptRecordClass);
@@ -532,14 +539,16 @@
     return factory.objectMembers.toString;
   }
 
-  private DexEncodedMethod synthesizeRecordInitMethod() {
+  private static DexEncodedMethod synthesizeRecordInitMethod(AppView<?> appView) {
     MethodAccessFlags methodAccessFlags =
         MethodAccessFlags.fromSharedAccessFlags(
             Constants.ACC_SYNTHETIC | Constants.ACC_PROTECTED, true);
     return DexEncodedMethod.syntheticBuilder()
-        .setMethod(factory.recordMembers.constructor)
+        .setMethod(appView.dexItemFactory().recordMembers.constructor)
         .setAccessFlags(methodAccessFlags)
-        .setCode(new CallObjectInitCfCodeProvider(appView, factory.recordTagType).generateCfCode())
+        .setCode(
+            new CallObjectInitCfCodeProvider(appView, appView.dexItemFactory().recordTagType)
+                .generateCfCode())
         // Will be traced by the enqueuer.
         .disableAndroidApiLevelCheck()
         .build();
diff --git a/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java b/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
index fd26662..13e2f29 100644
--- a/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
+++ b/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
 import com.google.common.collect.Sets;
 import java.nio.file.Path;
+import java.util.HashSet;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.junit.Test;
@@ -47,7 +48,7 @@
             .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(output))
             .build());
     CodeInspector inspector = new CodeInspector(output);
-    assertEquals(1023, inspector.allClasses().size());
+    assertEquals(1024, inspector.allClasses().size());
   }
 
   @Test
@@ -59,9 +60,16 @@
             .setMinApiLevel(AndroidApiLevel.LATEST.getLevel())
             .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(output))
             .build());
-    CodeInspector inspector = new CodeInspector(output);
-    // TODO(b/280016114): This will change when we have record tag.
-    assertEquals(0, inspector.allClasses().size());
+    Set<String> expectedInOutput = new HashSet<>();
+    // The output contains a RecordTag type that is mapped back to the original java.lang.Record by
+    // our codeinspector.
+    expectedInOutput.add("Ljava/lang/Record;");
+    assertEquals(
+        expectedInOutput,
+        new CodeInspector(output)
+            .allClasses().stream()
+                .map(FoundClassSubject::getFinalDescriptor)
+                .collect(Collectors.toSet()));
   }
 
   @Test