[Retrace] Extend retrace method arguments to account for spaces

Bug: b/301007957
Change-Id: If7af0e3ed1d7b978955f425254405ed592f92168
diff --git a/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxy.java b/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxy.java
index 08598e7..263ca19 100644
--- a/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxy.java
+++ b/src/main/java/com/android/tools/r8/retrace/StackTraceElementProxy.java
@@ -9,7 +9,9 @@
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.references.TypeReference;
-import java.util.Arrays;
+import com.google.common.base.Splitter;
+import java.util.ArrayList;
+import java.util.List;
 
 @Keep
 public abstract class StackTraceElementProxy<T, ST extends StackTraceElementProxy<T, ST>> {
@@ -42,6 +44,17 @@
 
   public abstract String getMethodArguments();
 
+  public List<TypeReference> getMethodArgumentTypeReferences() {
+    if (!hasMethodArguments()) {
+      return null;
+    }
+    List<TypeReference> typeReferences = new ArrayList<>();
+    for (String typeName : Splitter.onPattern(",\\s*").split(getMethodArguments())) {
+      typeReferences.add(Reference.typeFromTypeName(typeName));
+    }
+    return typeReferences;
+  }
+
   public abstract T toRetracedItem(
       RetraceStackTraceElementProxy<T, ST> retracedProxy, boolean verbose);
 
@@ -51,21 +64,21 @@
       mappingSupplier.registerClassUse(diagnosticsHandler, getClassReference());
     }
     if (hasMethodArguments()) {
-      Arrays.stream(getMethodArguments().split(","))
+      getMethodArgumentTypeReferences()
           .forEach(
-              typeName ->
-                  registerUseFromTypeReference(mappingSupplier, typeName, diagnosticsHandler));
+              typeReference ->
+                  registerUseFromTypeReference(mappingSupplier, typeReference, diagnosticsHandler));
     }
     if (hasFieldOrReturnType() && !getFieldOrReturnType().equals("void")) {
-      registerUseFromTypeReference(mappingSupplier, getFieldOrReturnType(), diagnosticsHandler);
+      registerUseFromTypeReference(
+          mappingSupplier, Reference.typeFromTypeName(getFieldOrReturnType()), diagnosticsHandler);
     }
   }
 
   private static void registerUseFromTypeReference(
       MappingSupplierBase<?> mappingSupplier,
-      String typeName,
+      TypeReference typeReference,
       DiagnosticsHandler diagnosticsHandler) {
-    TypeReference typeReference = Reference.typeFromTypeName(typeName);
     if (typeReference.isArray()) {
       typeReference = typeReference.asArray().getBaseType();
     }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
index 18623af..e8ef899 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
@@ -29,7 +29,6 @@
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.ListUtils;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.OptionalInt;
 import java.util.function.Consumer;
@@ -280,8 +279,8 @@
       return currentResult;
     }
     List<RetraceTypeResult> retracedResults =
-        Arrays.stream(element.getMethodArguments().split(","))
-            .map(typeName -> retracer.retraceType(Reference.typeFromTypeName(typeName)))
+        element.getMethodArgumentTypeReferences().stream()
+            .map(retracer::retraceType)
             .collect(Collectors.toList());
     List<List<RetracedTypeReference>> initial = new ArrayList<>();
     initial.add(new ArrayList<>());
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
index b7bdf62..9c8569f 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
@@ -312,8 +312,31 @@
                 if (!retraced.hasRetracedMethodArguments()) {
                   return original.getMethodArguments();
                 }
-                return StringUtils.join(
-                    ",", retraced.getRetracedMethodArguments(), RetracedTypeReference::getTypeName);
+                if (retraced.getRetracedMethodArguments().isEmpty()) {
+                  return "";
+                }
+                // Create a new arguments string matching the old one but maintain all spacing.
+                StringBuilder result = new StringBuilder();
+                String originalMethodArguments = original.getMethodArguments();
+                int argumentSeparatorIndex = 0;
+                boolean isNotFirst = false;
+                for (RetracedTypeReference retracedMethodArgument :
+                    retraced.getRetracedMethodArguments()) {
+                  if (isNotFirst) {
+                    result.append(",");
+                  }
+                  int spacesToInsert =
+                      StringUtils.firstNonWhitespaceCharacter(
+                              originalMethodArguments, argumentSeparatorIndex)
+                          - argumentSeparatorIndex;
+                  result.append(" ".repeat(spacesToInsert));
+                  result.append(retracedMethodArgument.getTypeName());
+                  argumentSeparatorIndex =
+                      originalMethodArguments.indexOf(',', argumentSeparatorIndex + spacesToInsert)
+                          + 1;
+                  isNotFirst = true;
+                }
+                return result.toString();
               });
       orderedIndices.add(methodArguments);
       return this;
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
index e75aad4..360621e 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
@@ -389,7 +389,11 @@
 
     @Override
     String subExpression() {
-      return "((" + JAVA_TYPE_REGULAR_EXPRESSION + "\\,)*" + JAVA_TYPE_REGULAR_EXPRESSION + ")?";
+      return "(("
+          + JAVA_TYPE_REGULAR_EXPRESSION
+          + "\\,\\s*)*"
+          + JAVA_TYPE_REGULAR_EXPRESSION
+          + ")?";
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java
index 7f22a4b..082fa95 100644
--- a/src/main/java/com/android/tools/r8/utils/StringUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -459,6 +459,15 @@
     return string.length();
   }
 
+  public static int firstNonWhitespaceCharacter(String string, int index) {
+    for (int i = index; i < string.length(); i++) {
+      if (!isWhitespace(string.charAt(i))) {
+        return i;
+      }
+    }
+    return string.length();
+  }
+
   public static String replaceAll(String subject, Map<String, String> map) {
     for (Entry<String, String> entry : map.entrySet()) {
       subject = replaceAll(subject, entry.getKey(), entry.getValue());
diff --git a/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java b/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
index abcf319..27e6084 100644
--- a/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
@@ -826,6 +826,87 @@
   }
 
   @Test
+  public void testArgumentsWithWhitespace() {
+    runRetraceTest(
+        "%c.%m\\(%a\\)",
+        new StackTraceForTest() {
+          @Override
+          public List<String> obfuscatedStackTrace() {
+            return ImmutableList.of("a.b.c.a(int, a.a.a[], a.b.c)");
+          }
+
+          @Override
+          public String mapping() {
+            return StringUtils.lines(
+                "com.android.tools.r8.D8 -> a.a.a:",
+                "com.android.tools.r8.R8 -> a.b.c:",
+                "  void foo(int,original.signature) -> a");
+          }
+
+          @Override
+          public List<String> retracedStackTrace() {
+            return ImmutableList.of(
+                "com.android.tools.r8.R8.foo"
+                    + "(int, com.android.tools.r8.D8[], com.android.tools.r8.R8)");
+          }
+
+          @Override
+          public List<String> retraceVerboseStackTrace() {
+            return ImmutableList.of(
+                "com.android.tools.r8.R8.void foo"
+                    + "(int,original.signature)"
+                    + "(int, com.android.tools.r8.D8[], com.android.tools.r8.R8)");
+          }
+
+          @Override
+          public int expectedWarnings() {
+            return 0;
+          }
+        });
+  }
+
+  @Test
+  public void testArgumentsWithDifferentWhitespace() {
+    runRetraceTest(
+        "%c.%m\\(%a\\)",
+        new StackTraceForTest() {
+          @Override
+          public List<String> obfuscatedStackTrace() {
+            return ImmutableList.of("a.b.c.a(int,a.a.a[], a.a.a,  a.b.c)");
+          }
+
+          @Override
+          public String mapping() {
+            return StringUtils.lines(
+                "com.android.tools.r8.D8 -> a.a.a:",
+                "com.android.tools.r8.R8 -> a.b.c:",
+                "  void foo(int,original.signature) -> a");
+          }
+
+          @Override
+          public List<String> retracedStackTrace() {
+            return ImmutableList.of(
+                "com.android.tools.r8.R8.foo(int,com.android.tools.r8.D8[],"
+                    + " com.android.tools.r8.D8,  com.android.tools.r8.R8)");
+          }
+
+          @Override
+          public List<String> retraceVerboseStackTrace() {
+            return ImmutableList.of(
+                "com.android.tools.r8.R8.void foo"
+                    + "(int,original.signature)"
+                    + "(int,com.android.tools.r8.D8[],"
+                    + " com.android.tools.r8.D8,  com.android.tools.r8.R8)");
+          }
+
+          @Override
+          public int expectedWarnings() {
+            return 0;
+          }
+        });
+  }
+
+  @Test
   public void testNoArguments() {
     runRetraceTest(
         "%c.%m\\(%a\\)",