Regression test for class inlining issue.

Bug: 160394262
Change-Id: I0d89ebb11e2cdfa1b4b0d337db99188126e33f89
diff --git a/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java b/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
new file mode 100644
index 0000000..b6dae6f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
@@ -0,0 +1,169 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.regress;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticException;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class Regress160394262Test extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("1;2;3");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+  }
+
+  public Regress160394262Test(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testReference() throws Exception {
+    testForRuntime(parameters)
+        .addInnerClasses(Regress160394262Test.class)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  // TODO(b/160394262): This should not fail to run.
+  @Test(expected = CompilationFailedException.class)
+  public void testR8() throws Exception {
+    // TODO(b/160394262): Only fails on DEX. Remove the assume once fixed so it runs CF and DEX.
+    assumeTrue(parameters.isDexRuntime());
+    testForR8(parameters.getBackend())
+        .allowAccessModification()
+        .addKeepMainRule(TestClass.class)
+        .addInnerClasses(Regress160394262Test.class)
+        .allowClassInlinerGracefulExit()
+        .compileWithExpectedDiagnostics(
+            diagnostics ->
+                // TODO(b/160394262): Remove once fixed.
+                diagnostics.assertErrorsMatch(diagnosticException(AssertionError.class)))
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  static class TestClass {
+
+    public void foo(List<?> items) {
+      System.out.println(Joiner.on(";").skipNulls().join(items));
+    }
+
+    public static void main(String[] args) {
+      new TestClass().foo(Arrays.asList("1", 2, 3l, null));
+    }
+  }
+
+  // Minimized copy of com.google.common.base.Preconditions
+  static class Preconditions {
+
+    public static <T> T checkNotNull(T reference) {
+      if (reference == null) {
+        throw new NullPointerException();
+      } else {
+        return reference;
+      }
+    }
+
+    public static <T> T checkNotNull(T reference, Object errorMessage) {
+      if (reference == null) {
+        throw new NullPointerException(String.valueOf(errorMessage));
+      } else {
+        return reference;
+      }
+    }
+  }
+
+  // Minimized copy of com.google.common.base.Joiner
+  static class Joiner {
+
+    private final String separator;
+
+    public static Joiner on(String separator) {
+      return new Joiner(separator);
+    }
+
+    private Joiner(String separator) {
+      this.separator = Preconditions.checkNotNull(separator);
+    }
+
+    private Joiner(Joiner prototype) {
+      this.separator = prototype.separator;
+    }
+
+    public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
+      Preconditions.checkNotNull(appendable);
+      if (parts.hasNext()) {
+        appendable.append(this.toString(parts.next()));
+        while (parts.hasNext()) {
+          appendable.append(this.separator);
+          appendable.append(this.toString(parts.next()));
+        }
+      }
+      return appendable;
+    }
+
+    public final String join(Iterable<?> parts) {
+      return join(parts.iterator());
+    }
+
+    public final String join(Iterator<?> parts) {
+      StringBuilder builder = new StringBuilder();
+      try {
+        appendTo((Appendable) builder, parts);
+        return builder.toString();
+      } catch (IOException e) {
+        throw new AssertionError(e);
+      }
+    }
+
+    public Joiner skipNulls() {
+      return new Joiner(this) {
+        public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts)
+            throws IOException {
+          Preconditions.checkNotNull(appendable, "appendable");
+          Preconditions.checkNotNull(parts, "parts");
+          Object part;
+          while (parts.hasNext()) {
+            part = parts.next();
+            if (part != null) {
+              appendable.append(Joiner.this.toString(part));
+              break;
+            }
+          }
+          while (parts.hasNext()) {
+            part = parts.next();
+            if (part != null) {
+              appendable.append(Joiner.this.separator);
+              appendable.append(Joiner.this.toString(part));
+            }
+          }
+          return appendable;
+        }
+      };
+    }
+
+    CharSequence toString(Object part) {
+      Preconditions.checkNotNull(part);
+      return part instanceof CharSequence ? (CharSequence) part : part.toString();
+    }
+  }
+}