blob: 383a7ef2a845f4261f13d289a26e084f29c2c71a [file] [log] [blame]
// 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.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
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 com.android.tools.r8.utils.codeinspector.CodeInspector;
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);
}
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.allowAccessModification()
.addKeepMainRule(TestClass.class)
.addInnerClasses(Regress160394262Test.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED)
.inspect(this::checkJoinerIsClassInlined);
}
private void checkJoinerIsClassInlined(CodeInspector inspector) {
assertThat(inspector.clazz(Joiner.class.getTypeName() + "$1"), not(isPresent()));
// TODO(b/160640028): When compiling to DEX the outer Joiner class is not inlined.
if (parameters.isDexRuntime()) {
assertThat(inspector.clazz(Joiner.class), isPresent());
} else {
assertThat(inspector.clazz(Joiner.class), not(isPresent()));
}
}
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();
}
}
}