Add builder for ForwardedSourceCode

Bug: 131885814
Change-Id: If91617dd57c95832c0431b08929fe8a69a370901
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 97fd72c..d916ee0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -742,22 +742,19 @@
         definitions.dexItemFactory().createMethod(method.holder, newProto, method.name);
     Builder builder = builder(this);
     builder.setMethod(newMethod);
+    ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+        ForwardMethodSourceCode.builder(newMethod);
+    forwardSourceCodeBuilder
+        .setReceiver(holder.type)
+        .setTargetReceiver(holder.type)
+        .setTarget(method)
+        .setInvokeType(Invoke.Type.DIRECT)
+        .setExtraNullParameter();
     builder.setCode(
         new SynthesizedCode(
-            callerPosition ->
-                new ForwardMethodSourceCode(
-                    holder.type,
-                    newMethod,
-                    newMethod,
-                    holder.type,
-                    method,
-                    Invoke.Type.DIRECT,
-                    callerPosition,
-                    holder.isInterface(),
-                    false,
-                    true),
-            registry -> registry.registerInvokeDirect(method)));
+            forwardSourceCodeBuilder::build, registry -> registry.registerInvokeDirect(method)));
     assert !builder.accessFlags.isStatic();
+    assert !holder.isInterface();
     builder.accessFlags.unsetPrivate();
     builder.accessFlags.setSynthetic();
     builder.accessFlags.setConstructor();
@@ -820,18 +817,16 @@
     DexMethod newMethod = definitions.dexItemFactory().createMethod(holder.type, proto, newName);
     Builder builder = builder(this);
     builder.setMethod(newMethod);
+    ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+        ForwardMethodSourceCode.builder(newMethod);
+    forwardSourceCodeBuilder
+        .setTargetReceiver(accessFlags.isStatic() ? null : method.holder)
+        .setTarget(method)
+        .setInvokeType(accessFlags.isStatic() ? Invoke.Type.STATIC : Invoke.Type.DIRECT)
+        .setIsInterface(holder.isInterface());
     builder.setCode(
         new SynthesizedCode(
-            callerPosition ->
-                new ForwardMethodSourceCode(
-                    null,
-                    newMethod,
-                    newMethod,
-                    accessFlags.isStatic() ? null : method.holder,
-                    method,
-                    accessFlags.isStatic() ? Invoke.Type.STATIC : Invoke.Type.DIRECT,
-                    callerPosition,
-                    holder.isInterface()),
+            forwardSourceCodeBuilder::build,
             registry -> {
               if (accessFlags.isStatic()) {
                 registry.registerInvokeStatic(method);
@@ -867,18 +862,17 @@
     } else {
       // Create code that forwards the call to the target.
       DexClass target = definitions.definitionFor(method.holder);
+      ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+          ForwardMethodSourceCode.builder(newMethod);
+      forwardSourceCodeBuilder
+          .setReceiver(accessFlags.isStatic() ? null : holder.type)
+          .setTargetReceiver(accessFlags.isStatic() ? null : method.holder)
+          .setTarget(method)
+          .setInvokeType(type)
+          .setIsInterface(target.isInterface());
       builder.setCode(
           new SynthesizedCode(
-              callerPosition ->
-                  new ForwardMethodSourceCode(
-                      accessFlags.isStatic() ? null : holder.type,
-                      newMethod,
-                      newMethod,
-                      accessFlags.isStatic() ? null : method.holder,
-                      method,
-                      type,
-                      callerPosition,
-                      target.isInterface()),
+              forwardSourceCodeBuilder::build,
               registry -> {
                 if (accessFlags.isStatic()) {
                   registry.registerInvokeStatic(method);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index 7f2bdf0..83ef838 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -112,22 +112,19 @@
     MethodAccessFlags newFlags = defaultMethod.accessFlags.copy();
     // Some debuggers (like IntelliJ) automatically skip synthetic methods on single step.
     newFlags.setSynthetic();
+    ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+        ForwardMethodSourceCode.builder(newMethod);
+    forwardSourceCodeBuilder
+        .setReceiver(clazz.type)
+        .setTarget(rewriter.defaultAsMethodOfCompanionClass(method))
+        .setInvokeType(Invoke.Type.STATIC)
+        .setIsInterface(target.isInterface());
     return new DexEncodedMethod(
         newMethod,
         newFlags,
         defaultMethod.annotations,
         defaultMethod.parameterAnnotationsList,
-        new SynthesizedCode(
-            callerPosition ->
-                new ForwardMethodSourceCode(
-                    clazz.type,
-                    newMethod,
-                    newMethod,
-                    null /* static method */,
-                    rewriter.defaultAsMethodOfCompanionClass(method),
-                    Invoke.Type.STATIC,
-                    callerPosition,
-                    target.isInterface())));
+        new SynthesizedCode(forwardSourceCodeBuilder::build));
   }
 
   // For a given class `clazz` inspects all interfaces it implements directly or
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
index 9c0c542..b2b88aa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
@@ -150,24 +150,21 @@
     newAccessFlags.setBridge();
     newAccessFlags.setSynthetic();
     DexMethod newMethod = factory.createMethod(method.method.holder, newProto, method.method.name);
+    ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+        ForwardMethodSourceCode.builder(newMethod);
+    forwardSourceCodeBuilder
+        .setReceiver(clazz.type)
+        .setTargetReceiver(method.method.holder)
+        .setTarget(method.method)
+        .setInvokeType(Invoke.Type.VIRTUAL)
+        .setCastResult();
     DexEncodedMethod newVirtualMethod =
         new DexEncodedMethod(
             newMethod,
             newAccessFlags,
             method.annotations.keepIf(x -> !isCovariantReturnTypeAnnotation(x.annotation)),
             method.parameterAnnotationsList.keepIf(Predicates.alwaysTrue()),
-            new SynthesizedCode(
-                callerPosition ->
-                    new ForwardMethodSourceCode(
-                        clazz.type,
-                        newMethod,
-                        newMethod,
-                        method.method.holder,
-                        method.method,
-                        Invoke.Type.VIRTUAL,
-                        callerPosition,
-                        false /* isInterface */,
-                        true /* castResult */)));
+            new SynthesizedCode(forwardSourceCodeBuilder::build));
     // Optimize to generate DexCode instead of SynthesizedCode.
     converter.optimizeSynthesizedMethod(newVirtualMethod);
     return newVirtualMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 48de822..e044477 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -227,6 +227,12 @@
 
       DexMethod origMethod = direct.method;
       DexMethod newMethod = rewriter.staticAsMethodOfDispatchClass(origMethod);
+      ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+          ForwardMethodSourceCode.builder(newMethod);
+      forwardSourceCodeBuilder
+          .setTarget(origMethod)
+          .setInvokeType(Type.STATIC)
+          .setIsInterface(true);
       DexEncodedMethod newEncodedMethod =
           new DexEncodedMethod(
               newMethod,
@@ -234,17 +240,7 @@
                   Constants.ACC_PUBLIC | Constants.ACC_STATIC | Constants.ACC_SYNTHETIC, false),
               DexAnnotationSet.empty(),
               ParameterAnnotationsList.empty(),
-              new SynthesizedCode(
-                  callerPosition ->
-                      new ForwardMethodSourceCode(
-                          null,
-                          newMethod,
-                          newMethod,
-                          null,
-                          origMethod,
-                          Type.STATIC,
-                          callerPosition,
-                          true /* isInterface */)));
+              new SynthesizedCode(forwardSourceCodeBuilder::build));
       newEncodedMethod.getMutableOptimizationInfo().markNeverInline();
       dispatchMethods.add(newEncodedMethod);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
index c49c3e1..e5a79bb 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -20,6 +20,87 @@
 // Source code representing simple forwarding method.
 public final class ForwardMethodSourceCode extends SyntheticSourceCode {
 
+  public static Builder builder(DexMethod method) {
+    return new Builder(method);
+  }
+
+  public static class Builder {
+
+    private DexType receiver;
+    private DexMethod method;
+    private DexMethod originalMethod;
+    private DexType targetReceiver;
+    private DexMethod target;
+    private Invoke.Type invokeType;
+    private boolean castResult;
+    private boolean isInterface;
+    private boolean extraNullParameter;
+
+    public Builder(DexMethod method) {
+      this.method = method;
+      this.originalMethod = method;
+    }
+
+    public Builder setReceiver(DexType receiver) {
+      this.receiver = receiver;
+      return this;
+    }
+
+    public Builder setMethod(DexMethod method) {
+      this.method = method;
+      return this;
+    }
+
+    public Builder setOriginalMethod(DexMethod originalMethod) {
+      this.originalMethod = originalMethod;
+      return this;
+    }
+
+    public Builder setTargetReceiver(DexType targetReceiver) {
+      this.targetReceiver = targetReceiver;
+      return this;
+    }
+
+    public Builder setTarget(DexMethod target) {
+      this.target = target;
+      return this;
+    }
+
+    public Builder setInvokeType(Type invokeType) {
+      this.invokeType = invokeType;
+      return this;
+    }
+
+    public Builder setCastResult() {
+      this.castResult = true;
+      return this;
+    }
+
+    public Builder setIsInterface(boolean isInterface) {
+      this.isInterface = isInterface;
+      return this;
+    }
+
+    public Builder setExtraNullParameter() {
+      this.extraNullParameter = true;
+      return this;
+    }
+
+    public ForwardMethodSourceCode build(Position callerPosition) {
+      return new ForwardMethodSourceCode(
+          receiver,
+          method,
+          originalMethod,
+          targetReceiver,
+          target,
+          invokeType,
+          callerPosition,
+          isInterface,
+          castResult,
+          extraNullParameter);
+    }
+  }
+
   private final DexType targetReceiver;
   private final DexMethod target;
   private final Invoke.Type invokeType;
@@ -27,51 +108,7 @@
   private final boolean isInterface;
   private final boolean extraNullParameter;
 
-  public ForwardMethodSourceCode(
-      DexType receiver,
-      DexMethod method,
-      DexMethod originalMethod,
-      DexType targetReceiver,
-      DexMethod target,
-      Type invokeType,
-      Position callerPosition,
-      boolean isInterface) {
-    this(
-        receiver,
-        method,
-        originalMethod,
-        targetReceiver,
-        target,
-        invokeType,
-        callerPosition,
-        isInterface,
-        false);
-  }
-
-  public ForwardMethodSourceCode(
-      DexType receiver,
-      DexMethod method,
-      DexMethod originalMethod,
-      DexType targetReceiver,
-      DexMethod target,
-      Type invokeType,
-      Position callerPosition,
-      boolean isInterface,
-      boolean castResult) {
-    this(
-        receiver,
-        method,
-        originalMethod,
-        targetReceiver,
-        target,
-        invokeType,
-        callerPosition,
-        isInterface,
-        castResult,
-        false);
-  }
-
-  public ForwardMethodSourceCode(
+  protected ForwardMethodSourceCode(
       DexType receiver,
       DexMethod method,
       DexMethod originalMethod,
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 25c61d8..e470a9b 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1886,16 +1886,16 @@
 
     @Override
     public SourceCodeProvider getSourceCodeProvider() {
-      return callerPosition ->
-          new ForwardMethodSourceCode(
-              method.holder,
-              method,
-              originalMethod,
-              type == DIRECT ? method.holder : null,
-              invocationTarget,
-              type,
-              callerPosition,
-              isInterface);
+      ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+          ForwardMethodSourceCode.builder(method);
+      forwardSourceCodeBuilder
+          .setReceiver(method.holder)
+          .setOriginalMethod(originalMethod)
+          .setTargetReceiver(type == DIRECT ? method.holder : null)
+          .setTarget(invocationTarget)
+          .setInvokeType(type)
+          .setIsInterface(isInterface);
+      return forwardSourceCodeBuilder::build;
     }
 
     @Override